Compare commits

..
Author SHA1 Message Date
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2c7d8411b9 Version Packages (#7863)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-18 12:25:40 -07:00
gregandGitHub 16ab7da64f [Dashboard] Fix: Do NOT use next's image component (#7869) 2025-08-18 12:18:03 -07:00
MananTank 467ba50907 [BLD-125] SDK: Fix missing props for details modal on useWalletDetailsModal hook (#7865)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `useWalletDetailsModal` hook by adding missing properties for better configuration of the details modal, along with adjustments to the UI components for displaying wallet details.

### Detailed summary
- Added missing props for the details modal in the `useWalletDetailsModal` hook.
- Updated `DetailsModal` to include `manageWallet`, `showBalanceInFiat`, and `hiddenWallets` props.
- Modified the `TokenTab` and `NftTab` components to use inline styles instead of utility classes.
- Enhanced storybook stories for `useWalletDetailsModal` with various configurations and examples.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- New Features
  - Wallet Details modal: show balances in fiat, configure manage-wallet options, hide specific wallets, and pass connect options from the switcher.
  - Assets view: default active tab now adapts dynamically based on available tabs.
- Documentation
  - Added comprehensive Storybook examples for the wallet details modal covering configuration, theming, locales, and callbacks.
  - Clarified notes to keep related modal options in sync.
- Style
  - Updated tab label styling to inline CSS for consistent layout.
- Chores
  - Added a patch-level changeset.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-19 00:14:53 +05:30
gregandGitHub 2f627e1483 [Dashboard] Feature: New payments page ui (#7848) 2025-08-18 11:41:49 -07:00
Jonas DanielsandGitHub 6b80f75e3a Make RPC optional in chain infrastructure checkout (#7867) 2025-08-18 11:36:54 -07:00
MananTank c43c686eac SDK, Dashboard: Fix error when airdropping decimal token amount in new token creation flow (#7866)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on changing the data type of the `amount` property in the `DistributeContent` type and related usages from `bigint` to `string` to accommodate string representations of numbers.

### Detailed summary
- Changed `amount` type in `DistributeContent` from `bigint` to `string`.
- Updated `amount` assignment in `create-token-page-impl.tsx` to use `recipient.quantity` directly as a `string`.
- Modified the total amount calculation to sum `recipient.quantity` as `Number` instead of `BigInt`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Fixed inconsistencies in token airdrop amount handling, ensuring accurate totals and smoother approvals.
  * Resolved submission issues caused by mismatched numeric formats during distribution.

* **Refactor**
  * Standardized how token distribution amounts are represented to improve compatibility with forms and API requests.
  * Simplified airdrop calculations for better reliability and user experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-18 17:42:55 +00:00
MananTank 92896ddf3f Create shared UI library - @workspace/ui (#7855)
created a @workspace/ui package - shared by dashboard and playground. for now it only has button component for testing

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `postcss` and `tailwind` configurations across multiple applications to centralize styles in the `@workspace/ui` package, along with various updates to components and layouts.

### Detailed summary
- Deleted `postcss.config.js` files and replaced them with `postcss.config.mjs` referencing `@workspace/ui`.
- Updated CSS imports to use `@workspace/ui/global.css`.
- Added `tailwindcss` configuration in `@workspace/ui` and updated references.
- Introduced new utility functions in `packages/ui/src/lib/utils.ts`.
- Modified component imports to utilize centralized components from `@workspace/ui`.
- Updated `package.json` files to include `@workspace/ui` as a dependency.
- Refactored button components to use a centralized button definition in `@workspace/ui`.
- Adjusted TypeScript configurations to align with the new structure.
- Enhanced global styles and configurations across multiple applications to ensure consistency.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - Added a shared UI package and unified Button component used across apps.

- Style
  - Apps now load shared global styles and animations from the UI package; global CSS and theme tokens consolidated.

- Bug Fixes
  - AI chat header uses a safe fallback when the client ID is missing.

- Refactor
  - Replaced local UI implementations with shared re-exports and composed Tailwind configs.

- Chores
  - Added UI package dependencies, PostCSS delegation, and enabled Next.js transpilation for the UI package; lint/scan ignore lists updated.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-16 12:58:24 +00:00
gregandGitHub a08b62be9a Feature: swapping guide (#7864) 2025-08-15 19:49:31 -06:00
MananTank 7f116577ab SDK: Fix PayEmbed not rendering anything when mode prop is not set (#7858)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `PayEmbed` component to default to a mode of "fund_wallet" with an amount of "0.01" and chain set to `ethereum` when no mode is specified. It also includes new story examples for the `PayEmbed` component.

### Detailed summary
- Deleted `PayEmbed.stories.ts` and test files.
- Updated `PayEmbed` component to default `mode` to "fund_wallet" and `amount` to "0.01".
- Added handling for `chain` defaulting to `ethereum`.
- Created multiple story functions for various use cases of `PayEmbed`.
- Included stories for different payment modes and configurations.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * PayEmbed now defaults to a wallet-funding flow when mode is missing (amount 0.01; Ethereum chain) and tolerates partial prefill data.

* **Enhancements**
  * Buy flow renders more flexibly when mode is omitted or set to fund_wallet.

* **Documentation**
  * Storybook updated/reorganized with comprehensive PayEmbed examples: fund wallet, direct payments, transactions, ERC20, metadata, and theme variants.

* **Chores**
  * Added a changeset for a patch release.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-15 23:28:17 +00:00
kumaryash90 d227bc389b Dashboard, SDK: ERC20 assets (#7321)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `thirdweb` package by introducing new functionalities and updates for managing ERC20 assets, including the implementation of various events, functions, and utility methods for asset deployment and interaction.

### Detailed summary
- Added `initialize` functions to various asset-related contracts.
- Introduced event handling for `AssetDistributed`, `RouterUpdated`, and `RewardLockerUpdated`.
- Implemented methods for checking router and reward locker support.
- Enhanced the `distributeToken` function to handle multiple recipients.
- Updated ABI files for new function signatures and events.
- Improved utility functions for encoding parameters and transaction preparation.

> The following files were skipped due to too many changes: `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/initialize.ts`, `packages/thirdweb/src/extensions/assets/__generated__/FeeManager/write/initialize.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/listAsset.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/distributeAsset.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAsset.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/sellAsset.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/buyAsset.ts`, `packages/thirdweb/src/extensions/assets/__generated__/ERC20Asset/write/initialize.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/addImplementation.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetById.ts`, `packages/thirdweb/src/extensions/assets/__generated__/AssetInfraDeployer/write/deployInfraProxyDeterministic.ts`, `packages/thirdweb/package.json`, `packages/thirdweb/src/extensions/assets/__generated__/AssetEntrypointERC20/write/createAssetByImplementationConfig.ts`, `packages/thirdweb/src/assets/bootstrap.ts`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added on-page Rewards workflow (Claim Rewards page, UI, and sidebar link) and expanded token creation flows for ERC20 assets with dedicated sale/airdrop options.

* **UI / UX**
  * Improved token sale & distribution UIs, grouped recent transfers, loading placeholders, styling tweaks, chain prioritization in network selectors, customizable wallet fallback icon, and chart legend/value display.

* **API / Props**
  * Several component props and callbacks updated to include chain/contract info and router availability.

* **Chores**
  * Release metadata added for an ERC20 assets patch.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-15 22:33:20 +00:00
Jonas DanielsandGitHub 6c711e8783 Rename /nebula to /ai and add redirect (#7862) 2025-08-15 15:11:56 -07:00
kumaryash90 6f581c80b3 Update default config (#7859)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on the removal of the `THIRDWEB_PUBLISHER_ADDRESS` constant from the `addresses.ts` file and its associated usage in the `custom-contract.tsx` file, simplifying the logic related to default fee configuration.

### Detailed summary
- Removed the `THIRDWEB_PUBLISHER_ADDRESS` constant from `addresses.ts`.
- Updated `custom-contract.tsx` to eliminate the use of `THIRDWEB_PUBLISHER_ADDRESS`.
- Simplified the `hasInbuiltDefaultFeeConfig` logic by only checking `defaultFeeRecipientFunction`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Corrected default platform-fee selection during contract deployment: when a default fee recipient is configured, the updated default fee rate is applied regardless of publisher identity, ensuring consistent platform fees on non–zero-fee chains.
* **Chores**
  * Removed an unused publisher address constant from configuration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-15 15:06:06 +00:00
MananTank b1ac15c2ac Dashboard: use BuyWidget instead of CheckoutWidget in TransactionButton (#7857)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `MismatchButton` component by replacing the `CheckoutWidget` with the `BuyWidget`, streamlining the payment interface.

### Detailed summary
- Replaced `CheckoutWidget` with `BuyWidget` in the render method of the `MismatchButton` component.
- Removed the `name` and `seller` props from the `BuyWidget`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* New Features
  * Introduced a new Buy experience in the pay dialog for adding funds.

* Improvements
  * Streamlined purchase flow with fewer required inputs and a cleaner interface.
  * Pay dialog can be opened and initiated without first connecting a wallet/account.
  * Consistent styling and theming applied across the new purchase widget.

* Chores
  * Updated dependencies to use the latest purchase widget component.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-14 20:05:26 +00:00
MananTank 98eefdf90b Dashboard: Fix No Funds PayEmbed in TransactionButton (#7856)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `MismatchButton` component by replacing the `PayEmbed` with `CheckoutWidget`, adjusting the transition duration in `DynamicHeight`, and streamlining the dialog content structure.

### Detailed summary
- Changed transition duration in `DynamicHeight` from `250ms` to `220ms`.
- Replaced `PayEmbed` with `CheckoutWidget` in the `MismatchButton` component.
- Simplified the dialog content structure by removing the `DynamicHeight` wrapper.
- Adjusted class names for consistency and clarity.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - “Not enough funds” flow now uses a new checkout widget and only appears when your account is connected.

- Style
  - Payment dialog is wider and uses full available width for improved readability.
  - Spacing and layout refined for a cleaner experience.
  - Slightly faster height transition animations for snappier UI feedback.

- Refactor
  - Simplified dialog content by removing an extra height wrapper.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-14 18:58:15 +00:00
MananTank 857d4dfc16 Playground: Fix theme toggle UI when sidebar is collapsed (#7853)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refining the sidebar component in the application by adjusting styles, modifying the theme toggle functionality, and enhancing the UI elements for better user experience.

### Detailed summary
- Updated `SIDEBAR_WIDTH` and `SIDEBAR_WIDTH_MOBILE` from `"19rem"` to `"18rem"`.
- Removed `ChevronDownIcon` and replaced it with `ChevronRightIcon` in `RenderSidebarSubmenu`.
- Added `<SidebarSeparator />` in `FullWidthSidebarLayoutInner`.
- Replaced `Button` with `SidebarMenu`, `SidebarMenuButton`, and `SidebarMenuItem` in `ThemeToggle`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - Theme toggle now appears as a sidebar menu item with improved loading placeholders for icon and label.
- UI/UX
  - Sidebar width reduced from 19rem to 18rem for a more compact layout.
  - Chevron indicators updated: right-chevron rotates 90° when open for clearer state.
  - Added a visual separator in the sidebar footer for better grouping.
- Bug Fixes
  - Prevented rendering of empty sidebar menus/submenus.
- Refactor
  - Streamlined imports and removed unused variants; maintained existing toggle behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-13 23:35:36 +00:00
MananTank 22aad59e7d Dashboard: Fix Active Users calculation in team and project analytics charts (#7854)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on modifying the `aggregateFn` function in two files related to analytics highlights cards, ensuring consistent functionality for aggregating data.

### Detailed summary
- In both `highlights-card.tsx` files, the `aggregateFn` function is updated to include logic for handling the `activeUsers` key.
- The function calculates the maximum value for `activeUsers` and sums values for other keys.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Standardized analytics aggregation across Highlights cards. All metrics, including Active Users, now show the total over the selected period (previously Active Users showed the peak value). Expect updated figures in both Team Analytics Highlights and Project Overview Highlights, ensuring consistency between summary cards and detailed views.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-13 18:47:23 +00:00
Joaquim VergesandGitHub a3b2f8f4b0 [Playground] integration guide link in chat ai footer (#7852) 2025-08-12 19:10:00 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
d617bf77b3 Version Packages (#7851)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 18:39:30 -07:00
Joaquim VergesandGitHub 4be655dd08 [SDK] Fix onDisconnect callback not being invoked in React Native (#7850) 2025-08-12 18:18:45 -07:00
MananTank 74d4074f42 Dashboard: Add fallback to native token balance on contract/split page when insight is not supported (#7847)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the handling of token balances and recipient percentages in the `ContractSplitPage` and related components, enhancing user experience and error handling.

### Detailed summary
- Updated `transactionCount` logic in `DistributeButton` to handle undefined cases.
- Added error handling for fetching token balances using `tryCatch`.
- Improved UI structure and styling in `ContractSplitPage`.
- Changed variable naming for clarity in `useReadContract`.
- Enhanced loading states for recipient percentages and balances.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved reliability of token balances by falling back to native balance if token data fails to load.
* **Style**
  * Refreshed Split page layout: simplified headers, refined spacing, and updated table containers.
  * Adjusted column widths for Tokens and Addresses for better readability.
  * Enhanced loading skeletons and maintained clear empty/error states.
* **Refactor**
  * Streamlined data flow for recipients and balances to use a unified query object.
* **Chores**
  * Button tweaks: small size on error; hide transaction count when only one transaction.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-12 23:41:08 +00:00
MananTank a36c850b86 [BLD-108] Dashboard: Update Claim conditions UI to handle very large snapshots (#7846)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the handling of CSV uploads and snapshots in the dashboard, improving user feedback during data processing, and refining the management of claim conditions within the application.

### Detailed summary
- Updated `package.json` to remove `p-limit`.
- Improved UI for CSV upload status with additional messages.
- Refactored snapshot management in `ClaimConditionsForm`.
- Added state for `phaseSnapshots` to optimize performance.
- Enhanced snapshot handling in `SnapshotUpload` component.
- Updated data processing logic in `useCsvUpload` to track progress.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - CSV upload shows real-time normalization progress and ENS resolution status across relevant upload screens; pending states now display current/total progress.
  - Per-phase snapshot management with centralized state; improved snapshot viewer with view/edit modes, pagination, and clearer labels.
  - Improved validation: invalid addresses highlighted with tooltips and options to remove or proceed.

- Refactor
  - CSV normalization switched to batched processing for smoother, more responsive uploads.
  - Snapshot data moved out of per-field form state to reduce rendering overhead.

- Chores
  - Removed an unused dependency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-12 22:55:13 +00:00
59a8dad48e [Playground] ai chat demo (#7833)
Co-authored-by: Cursor Agent <[email protected]>
2025-08-12 15:17:03 -07:00
MananTank f7aa3e6239 [BLD-80] Dashboard: in-app wallet settings page UI improvements (#7843)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the UI components and improving the country selection functionality in the dashboard application. It includes updates to transitions, checkbox indicators, and country names for better clarity and usability.

### Detailed summary
- Updated transition duration in `DynamicHeight.tsx`.
- Added `MinusIcon` for indeterminate state in `checkbox.tsx`.
- Corrected country names in `utils.ts` for several countries.
- Improved structure and styling of the `CountrySelector` component.
- Added `ChevronDownIcon` and `Button` for toggling tiers in `country-selector.tsx`.
- Refactored `Fieldset` and `FieldsetWithDescription` components for better layout and usability in settings forms.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- New Features
  - Checkbox now supports an indeterminate state with a clear visual indicator.
  - Wallet settings sections gain per-section Save buttons with loading spinners.
  - SMS country selection adds collapsible tier cards, partial-selection counters, and improved country tiles with clear selection states.

- Refactor
  - Unified fieldset layouts with consistent headers, descriptions, dividers, and footers.
  - Branding settings reorganized into a responsive two‑column layout with improved flow.
  - Country tier rendering moved to modular TierCard components.

- Bug Fixes
  - Corrected several country display names (e.g., South Korea, North Macedonia, Eswatini, Saint Lucia).

- Style
  - Adjusted a height-transition timing/easing for dynamic-height animations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-12 21:41:49 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
827819b911 Version Packages (#7826)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-12 12:41:39 -06:00
gregfromstl 0d7e5e563d [SDK] Fix: Process undefined checks in vite (#7844)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR addresses the resolution of the SDK in environments where `process` is undefined, ensuring that the checks for development and test environments are more robust.

### Detailed summary
- Updated the `IS_DEV` constant to check if `process` is defined before accessing its properties.
- Modified the `IS_TEST` constant similarly to ensure it only evaluates when `process` is defined.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Guarded environment checks to avoid runtime errors where Node globals are absent, improving stability across browsers, serverless, and edge runtimes.
  * More reliable detection of development and test modes, reducing unexpected crashes during bundling, CI testing, and client-side use.

* **Chores**
  * Added release metadata so the fix will be published as a patch.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-12 18:07:25 +00:00
Joaquim VergesandGitHub 8665e8fe14 [Portal] Improve responsive layout for request example header (#7841) 2025-08-12 03:11:29 -07:00
438027a40e [Docs] Replace custom API endpoint with OpenAPI component (#7829)
Co-authored-by: 0xFirekeeper <[email protected]>
2025-08-12 16:28:14 +12:00
FirekeeperandGitHub 66c7df98e4 Add TikTok as auth method for In-App and Ecosystem Wallets (#7817) 2025-08-11 20:02:58 -07:00
gregandGitHub 409ae17c15 Fix: Hide manage contract button when foreign wallet (#7832) 2025-08-11 20:55:47 -06:00
Joaquim VergesandGitHub be28b0c26e [Docs] Add AI Chat API documentation and endpoint metadata (#7828) 2025-08-11 19:45:48 -07:00
gregandGitHub c661a485d0 [Dashboard] Fix: change payment links -> payments (#7831) 2025-08-11 12:43:28 -06:00
gregandGitHub 90f36bc414 [SDK] Refactor: Only show user balances in payment selection screens (#7827) 2025-08-11 09:50:15 -06:00
gregandGitHub a77e98a48a [SDK] Fix: Deprecate bridge routes sortBy (#7825) 2025-08-10 19:03:26 -06:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
fde39eb883 Version Packages (#7820)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-10 16:25:15 -07:00
c672a84fc3 Add chinese locale to connect button (#7807)
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: yashjoisar <[email protected]>
2025-08-10 16:17:18 -07:00
Joaquim VergesandGitHub d52855dbda [SDK] Fix supportedTokens address comparison in usePaymentMethods (#7824) 2025-08-10 16:16:11 -07:00
MananTank a3909e1794 Add caching to ContractCard, speed up /explore pageload (#7822)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `ContractRow`, `ContractPublisher`, and `ContractCard` components to streamline their props and improve caching mechanisms for fetching contract data.

### Detailed summary
- Simplified `ContractRow` props by removing the interface.
- Refactored `ContractPublisher` to use props directly instead of an interface.
- Updated `ContractPublisher` to utilize `Img` and `Blobbie` for avatar rendering.
- Introduced caching for `fetchPublishedContractVersion` and `resolvePublisherEnsAndAvatar`.
- Changed how `ContractPublisher` is rendered in `ContractCard` to use new props structure.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Improved performance and consistency for contract publisher information by introducing server-side caching for contract version data and publisher ENS details.
  * Enhanced publisher display with avatars and ENS names, including fallback visuals when no avatar is available.

* **Refactor**
  * Streamlined the contract publisher display by replacing the previous component with a simplified implementation accepting explicit props.
  * Updated type definitions for improved code clarity without affecting user-facing behavior.

* **Chores**
  * Minor import and type annotation adjustments for better maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-09 15:59:46 +00:00
nischitpra f92201d353 webhook multiselect topic (#7818)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on modifying the handling of `sigHash` to support both single and multiple signature inputs across various components, improving user experience and functionality.

### Detailed summary
- Changed `sigHash` from a string to an array in multiple components.
- Updated validation and handling of `sigHash` in forms and utilities.
- Enhanced UI to reflect multiple signature selections.
- Adjusted props and methods to support multi-select functionality in `SignatureSelector` and related components.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added support for selecting multiple signature hashes in webhook filters and selectors.
  * Enhanced signature selectors to allow both single-select and multi-select modes, with improved handling of custom signatures.

* **Improvements**
  * Updated UI labels, placeholders, and descriptions to reflect multi-selection capabilities and pluralization.
  * Review and summary steps now display multiple selected signatures with appropriate formatting.
  * Webhook payloads and validation schemas now support arrays of signature hashes for improved flexibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-08 20:18:28 +00:00
gregandGitHub 45ba811950 [SDK] Fix: Sort payment quotes in ascending order (#7819) 2025-08-08 12:42:53 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
7c458eaa49 Version Packages (#7814)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-08 11:04:39 -07:00
gregandGitHub f7ce6becd6 [SDK] Fix: Adds onExecuteTransaction to TransactionPayment (#7816) 2025-08-07 20:27:27 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
52d1ba32c4 Chore(deps): Bump viem from 2.28.1 to 2.33.2 (#7793)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-07 18:31:12 -07:00
saminacodes 1a7315c815 arb-docs (#7799)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances the documentation for thirdweb's `Stylus` contracts, detailing the deployment and usage of `Stylus` contracts and `Airdrop` contracts on the `Arbitrum` network, including benefits, prerequisites, and step-by-step tutorials.

### Detailed summary
- Added a new section on `Contract security` in `page.mdx`.
- Updated `sidebar.tsx` to include collapsible sections for `Arbitrum Stylus` with links to contract deployment guides.
- Created detailed documentation for `Stylus Contracts` and `Stylus Airdrop Contracts` in their respective `page.mdx` files, including benefits, prerequisites, and step-by-step deployment instructions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Documentation**
  * Added a new page detailing Stylus Airdrop Contract deployment and usage on Arbitrum, including multiple airdrop patterns and integration examples.
  * Introduced a guide for deploying Stylus contracts on Arbitrum, covering project setup, deployment, and NFT minting.
  * Added a contract security section highlighting third-party audits and linking to audit reports.
  * Updated the sidebar with a new "Arbitrum Stylus" section for easier navigation to Stylus contract guides.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-08 00:48:15 +00:00
gregandGitHub 50c6c193c6 [SDK] Fix: Bridge.tokens domain (#7815) 2025-08-07 16:55:42 -07:00
gregandGitHub e114b2c4f9 [SDK] Fix: Skip payment method selection when balance is sufficient (#7813) 2025-08-07 16:37:53 -07:00
MananTank d812cc370b [MNY-92] Dashboard: Add tokens section in explore (#7812)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the project selection and token creation flow within the dashboard application. It includes the addition of new components, updates to existing ones, and enhancements to user notifications and alerts.

### Detailed summary
- Updated import paths for `project-selector` and `team-selector`.
- Added `TokenBanner` component for displaying token creation options.
- Enhanced `DismissibleAlert` to support conditional rendering based on visibility state.
- Introduced `GenericProjectSelector` for improved project selection.
- Modified `ExplorePage` layout and styling for better presentation.
- Added `TokensSection` component with links for launching tokens and NFTs.
- Updated `reportTokenUpsellClicked` function for event tracking.
- Improved UI elements for better user experience and responsiveness.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced a "Tokens" section on the Explore page, showcasing options for creating ERC-20 tokens (Coins) and NFT Collections.
  * Added a promotional token banner on deploy pages for select published token contracts.
  * Launched a new project selection page within the team context, streamlining project navigation and selection.
  * Added a generic project selector component to enhance project selection flexibility.
  * Added tracking for clicks on token creation cards and token upsell banner interactions to improve analytics.

* **Improvements**
  * Enhanced layout and styling of the Explore page for better readability and organization.
  * Updated project and team selector components for more flexible descriptions and improved navigation.
  * Updated team page alert to preserve dismissal state across sessions.

* **Chores**
  * Refined import paths for improved code organization and maintainability.
  * Refactored dismissible alert component to support optional state persistence.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-07 20:45:31 +00:00
MananTank 7883127d51 Dashboard: Add caching to analytics charts (#7804)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the analytics functionality across various components by adding an `authToken` parameter to API calls, ensuring secure access to analytics data.

### Detailed summary
- Added `authToken` prop to multiple components for secure API access.
- Updated API functions to accept `authToken` for authentication.
- Modified analytics data fetching methods to include `authToken`.
- Changed default values and parameters in several functions for consistency.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Analytics data fetching now uses caching for improved performance.
  * Authentication is enforced for all analytics-related pages and components, with users redirected to login if not authenticated.

* **Refactor**
  * All analytics API calls and related components now require an explicit authentication token, improving security and consistency.
  * Parameters for analytics functions and components are more consistently structured, often grouped into objects for clarity.

* **Style**
  * Default chart display updated from "totalVolume" to "activeUsers" in highlights cards for a more relevant initial view.

* **Bug Fixes**
  * Standardized error handling across analytics data requests.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-07 14:33:04 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
53d0d74d9b Version Packages (#7810)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-07 02:59:39 -07:00
Joaquim VergesandGitHub c0948fb9fe [SDK] Handle environments where process is not defined (#7809) 2025-08-07 02:48:44 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
9ae2991ad7 Version Packages (#7806)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-06 19:24:10 -07:00
MananTank bab4ff5e14 Dashboard: Improved chart responsiveness, code cleanup (#7801)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing analytics components by introducing responsive time filters, updating chart components to support new props, and refactoring existing code for improved clarity and functionality.

### Detailed summary
- Removed `range-selector.tsx` and refactored `AnalyticsHeader.tsx`.
- Added `ResponsiveTimeFilters` for better time range handling.
- Updated `EcosystemWalletsSummary` and `EcosystemAnalyticsPage` to use new props.
- Refactored various chart components to accept `selectedChart` and `selectedChartQueryParam`.
- Enhanced `AsyncTransactionsChartCard` and `AsyncTotalSponsoredCard` for better data handling.
- Replaced `LoadingChartState` with responsive loading states across components.
- Consolidated logic for handling time series data in analytics cards.
- Improved type definitions for better clarity and consistency.

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced responsive and modular time filter controls for analytics dashboards.
  * Added new highlights cards for team and project analytics, providing aggregated metrics in a combined bar chart format.
  * Added a new combined bar chart card for gas sponsorship data with dynamic chart selection.
  * Added components that map transaction and sponsorship data with chain metadata for improved analytics detail.

* **Refactor**
  * Replaced multiple analytics and chart components with streamlined, asynchronous, and responsive variants.
  * Standardized date range and interval filtering using a centralized utility and responsive providers.
  * Updated chart selection to use in-app state and callbacks instead of URL-based navigation.
  * Simplified analytics page layouts by replacing Suspense with responsive suspense components.
  * Externalized data processing and state management from several chart card components to improve modularity.
  * Removed deprecated components and replaced them with updated responsive and async implementations.

* **Bug Fixes**
  * Improved handling of date ranges and intervals, ensuring accurate and consistent filtering.

* **Chores**
  * Removed unused or redundant components and consolidated stories for better maintainability.
  * Cleaned up imports and type definitions across analytics and project overview pages.

* **Style**
  * Enhanced button and layout styling for chart selection and analytics cards.

* **Documentation**
  * Updated interactive stories for analytics components to improve clarity and usability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-07 01:24:29 +00:00
621c1de62e [SDK] Add buttonLabel prop to checkout widgets (#7805)
Co-authored-by: Cursor Agent <[email protected]>
2025-08-06 18:23:53 -07:00
Joaquim VergesandGitHub 8bb2b0a227 [Docs] Update pregenerate wallets API endpoint and request format (#7791) 2025-08-06 13:49:16 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
5f82df1652 Version Packages (#7776)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-06 12:17:01 -07:00
MananTank fd4414b451 [BLD-71] SDK, Dashboard: Fix Supplies shown in ERC721 contract (#7803)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the `getTotalClaimedSupply` and `getTotalUnclaimedSupply` functions in the ERC721 extensions to account for `startTokenId`, improving the accuracy of token supply calculations.

### Detailed summary
- Modified `getTotalClaimedSupply` to subtract `startTokenId` from `nextTokenIdToClaim`.
- Updated `getTotalUnclaimedSupply` to subtract `startTokenId` and `totalClaimedSupply` from `nextTokenIdToMint`.
- Changed imports in `supply-cards.tsx` to use the new supply functions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Improved supply calculations in NFT dashboards by directly using contract data instead of manual computations.
  * Adjusted logic to accurately account for token ID offsets when displaying claimed and unclaimed NFT supply.

* **Bug Fixes**
  * Resolved inconsistencies in claimed and unclaimed NFT supply values when contracts use a custom starting token ID.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-06 18:53:42 +00:00
MananTank d10436d3d2 Dashboard: Add tracking for fund wallet modal (#7800)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the analytics tracking for the `FundWalletModal` component by adding new reporting functions and integrating them into the wallet funding process.

### Detailed summary
- Added `reportFundWalletOpened` function to track when the fund wallet modal is opened.
- Integrated `reportFundWalletOpened` call in `BackendWalletsTable` when the fund wallet button is clicked.
- Added `reportFundWalletSuccessful` and `reportFundWalletFailed` functions to track successful and failed fund wallet transactions.
- Integrated success and error reporting in the `FundWalletModal` component.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added analytics tracking for opening the fund wallet modal, successful wallet funding, and failed wallet funding attempts, including error reporting.
  * Enhanced the fund wallet experience with event reporting on user actions for improved insights.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-06 17:37:19 +00:00
MananTank 56b12c6094 Dashboard: export the date in CSV as ISO string in wallets/users table, UI tweaks (#7802)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances the `AdvancedSearchInput` component by adding a clear button, improving the layout, and integrating a loading spinner. It also updates the `InAppWalletUsersPageContent` to include a tooltip for user identifiers and modifies the display of created dates.

### Detailed summary
- Added `XIcon` to `AdvancedSearchInput` for a clear button.
- Integrated `Spinner` for loading state in `AdvancedSearchInput`.
- Improved layout with responsive design adjustments.
- Added `ToolTipLabel` for user identifier display in `InAppWalletUsersPageContent`.
- Changed date format to ISO in `InAppWalletUsersPageContent`.
- Updated button styles for better UI consistency.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added an inline clear button ("X" icon) to the search input, allowing users to clear queries directly.
  * User identifiers now feature a copy-to-clipboard button with truncation and tooltip support.
  * Wallet creation dates now display detailed timestamps in a tooltip on hover.

* **Improvements**
  * Enhanced responsive layout for search input and controls, optimizing usability across devices.
  * Updated button styles and input appearance for a more cohesive look.
  * CSV export now uses ISO date format for wallet creation dates.
  * Improved font size and styling for wallet labels and download button.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-06 17:27:06 +00:00
abbdb0f113 Rename archive to advanced sidebar (#7798)
Co-authored-by: Cursor Agent <[email protected]>
2025-08-05 17:37:25 -07:00
MananTank d05dbcb5ac Dashboard: enforce absolute imports for '@' folder (#7796)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds a new ESLint rule to enforce the use of absolute imports in the `apps/dashboard/.eslintrc.js` configuration file.

### Detailed summary
- Introduced a `patterns` array to the ESLint configuration.
- Added a rule that restricts the use of relative imports, prompting users to use absolute imports instead.
- Provided an example of the correct import format: `'@/foo/bar'`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Chores**
  * Updated code style rules to enforce the use of absolute imports instead of certain relative import patterns.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-05 23:29:57 +00:00
Jonas DanielsandGitHub 3a52f9d486 Add posthog.com and framer.com to CSP (#7797) 2025-08-05 16:26:26 -07:00
Joaquim VergesandGitHub 9a3ebe1cb1 [SDK] Add transaction hash to max wait time error (#7789) 2025-08-04 17:17:05 -07:00
MananTank ad2d22558b Dashboard: File organization changes (#7788)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added a hook to fetch favorite chain IDs for user accounts.
  * Introduced contract verification functionality.
  * Added UI for saving deployed contracts to projects.
  * Provided new lightweight types for teams and projects.

* **Bug Fixes**
  * Replaced NFT media cell rendering in marketplace tables for improved display and interaction.

* **Refactor**
  * Standardized and reorganized import paths across the app for improved maintainability.
  * Renamed and updated fieldset components in contract deployment forms for consistency.
  * Centralized and simplified cookie and authentication token handling.
  * Removed or relocated obsolete and redundant components and types.

* **Chores**
  * Cleaned up unused files and consolidated constants.
  * Updated and clarified type imports throughout the codebase.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-04 21:37:15 +00:00
MananTank 0aac9a8593 Dashboard: dedicated engine header UI tweak on mobile, Tab component tweaks (#7787)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `TabButtons` component across various files by modifying class names and adjusting properties to improve styling and functionality.

### Detailed summary
- Updated `tabClassName` for `TabButtons` in multiple files to enhance styling.
- Changed `tabContainerClassName` in several instances to adjust layout.
- Added `activeTabClassName` in certain components to manage active tab styles.
- Refined `isActive` logic for better tab state management.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Style**
  * Updated tab button styling across multiple areas of the dashboard for a more consistent appearance, removing explicit small text overrides and adjusting layout and padding.
  * Improved header layout and button appearance in the transactions section for better responsiveness and visual clarity.
  * Enhanced code snippet formatting in API usage examples for readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-04 20:47:42 +00:00
saminacodes fa7a81260d added wallets seo, fixed faqs, added deployment guides (#7786)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating documentation and content related to thirdweb's tokens, wallets, and contracts. It enhances clarity, adds new features, and improves user guidance across various sections.

### Detailed summary
- Added new images for token deployment and wallet features.
- Updated titles and descriptions for clarity in multiple `.mdx` files.
- Introduced new sections and links in the sidebar for better navigation.
- Enhanced FAQs with specific details about tokens and wallet security.
- Added guides for deploying ERC-20 and ERC-721 tokens.
- Updated resource links and documentation structure for improved user experience.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an "Insight" navigation link to the main header.
  * Introduced new documentation pages: Modular Contracts overview, ERC-20, ERC-721, and ERC-1155 token deployment guides, token listing placeholder, and troubleshooting guides for contracts.
  * Added new FAQ pages for contracts and expanded FAQs for payments, tokens, and wallets.

* **Documentation**
  * Improved and expanded metadata (titles, descriptions, images) for multiple documentation pages for better clarity and SEO.
  * Updated and restructured sidebar navigation for Contracts, Tokens, Transactions, and Wallets sections, including new links, reorganized groups, and resource sections.
  * Enhanced FAQ formatting with collapsible sections and improved content clarity across several pages.
  * Streamlined and updated content in various wallet and contract documentation pages.

* **Style**
  * Improved documentation structure and presentation, including use of collapsible details and better grouping of related topics.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-04 17:54:57 +00:00
Alec AnanianandGitHub e5326c43a9 [SDK] Feat: export useSiweAuth for React Native (#7785) 2025-08-03 10:41:21 +12:00
MananTank 57862d0bd0 Playground: Improved sidebar search params suspense fallback, Fix ConnectEmbed width on mobile (#7784)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing layout responsiveness and improving the rendering of sidebar components by integrating full path management, along with some styling adjustments.

### Detailed summary
- Added `className="!max-w-full"` to various components for responsive design.
- Wrapped `StyledConnectEmbed` in a div with overflow and padding.
- Changed heading and paragraph styles in `APIHeader`.
- Introduced `FullPathSuspense` for managing full path rendering.
- Modified `NavLink` to accept `fullPath` prop.
- Updated sidebar components to use `fullPath` for link matching.
- Removed unnecessary `Suspense` wrappers from sidebar rendering functions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced a component that enables rendering content based on the full current URL path, including query parameters.

* **Refactor**
  * Updated sidebar and navigation components to receive the current path as a prop, simplifying active link determination and layout logic.
  * Consolidated suspense handling for sidebar components to a single top-level boundary.

* **Style**
  * Improved visual layout and spacing for embedded components and page headers.
  * Enhanced responsiveness and maximum width handling for embedded connect components.

* **Documentation**
  * Updated type names and component signatures for improved clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-02 20:16:05 +00:00
MananTank 834bbc0883 [MNY-62] Dashboard: Add CheckoutWidget in server wallets & backend wallets table. server wallets UI improvements (#7782)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the dashboard application with various improvements, including dependency updates, UI adjustments, and the introduction of new components for better wallet management.

### Detailed summary
- Removed `react-qrcode-logo` from dependencies.
- Changed `tabNames` in `IntegrateAPIKeyCodeTabs.tsx`.
- Updated button structure in `layout.tsx` for better UI.
- Adjusted styles in `wallet-address.tsx` for consistency.
- Modified `PaymentLinksTable.client.tsx` button variants and sizes.
- Removed unused imports in `page.tsx`.
- Enhanced `Switch` component with size prop.
- Added `FundWalletModal` component with form validation.
- Updated `ServerWalletsTableUI` with improved wallet display and functionality.
- Introduced `WalletActionsDropdown` for wallet actions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced a modal for funding wallets, allowing users to select chain, token, and amount, and complete payments via a checkout flow.
  * Added chain selection and a toggle to display ERC4337 Smart Accounts in the server wallets table.
  * Enhanced wallet actions with a dropdown menu for sending test transactions and funding wallets.

* **UI Improvements**
  * Updated wallet and smart account tables with improved layout, balance refresh, and modular components.
  * Refined button and modal styles across various components for a more consistent look and feel.
  * Adjusted the size of wallet avatars and icons for better visual balance.
  * Simplified and clarified descriptive text in payment links and wallet creation dialogs.
  * Improved switch component with a smaller size variant option.
  * Modified tab order in API key integration for better user flow.
  * Updated transaction page button styling and composition.

* **Bug Fixes**
  * Removed the QR code-based receive funds modal, replacing it with the new funding modal.

* **Chores**
  * Removed an unused dependency related to QR code generation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-02 02:24:48 +00:00
MananTank 3a9aa1a72b Dashboard: Fix Payment link buy completion tracking (#7783)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on simplifying the `reportPaymentLinkBuySuccessful` and `reportPaymentLinkBuyFailed` functions by removing unnecessary parameters and adjusting their calls accordingly.

### Detailed summary
- Removed `linkId` and `clientId` parameters from the `reportPaymentLinkBuySuccessful` function.
- Adjusted the call to `reportPaymentLinkBuySuccessful` in `PayPageWidget.client.tsx` to no longer pass parameters.
- Simplified the call to `reportPaymentLinkBuyFailed` by removing `linkId` and `clientId` parameters and retaining only `errorMessage`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Streamlined payment reporting by simplifying success and failure event tracking. Payment success is now always reported without additional details, and payment failure reports only include the error message. No impact on payment or redirect flows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-02 02:10:19 +00:00
Joey BrightandGitHub 572368edc3 chore: fix typos in docs (#7777) 2025-08-01 16:52:45 -07:00
MananTank 9b5ca42091 Dashboard: Remove unused envs from .env.example and turbo config (#7779)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on cleaning up the environment variables in the `turbo.json` and `.env.example` files, removing several unused keys and updating comments for clarity.

### Detailed summary
- Removed multiple environment variables from `turbo.json`.
- Updated comments and reorganized sections in `apps/dashboard/.env.example`.
- Added `NEXT_PUBLIC_THIRDWEB_VAULT_URL` and `NEXT_PUBLIC_ENGINE_CLOUD_URL` as required.
- Clarified purpose for `DASHBOARD_SECRET_KEY` and `API_ROUTES_CLIENT_ID`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Chores**
  * Cleaned up and reorganized environment variable examples for improved clarity and usability.
  * Removed deprecated and unused environment variables.
  * Updated placeholder formatting and improved instructions for setting required variables.
  * Simplified and reduced the environment variable list used during dashboard build tasks.
  * Added new environment variables for insight service and Stripe integration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 20:59:25 +00:00
MananTank c6849a8734 [MNY-61] Dashboard: Tokens and Payments tracking updates (#7781)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the payment link functionality and analytics reporting within the application. It introduces new hooks, modifies existing components, and refines analytics events to improve tracking and user experience.

### Detailed summary
- Added `useEffectOnce` hook for single execution of effects.
- Implemented `AssetPageView` component to report asset page views.
- Updated `CreatePaymentLinkButton` to report link creation.
- Enhanced payment link reporting with success and failure events.
- Removed unused analytics functions related to asset creation.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-08-01 20:09:00 +00:00
gregandGitHub 7617cc84fc [SDK] Fix: Respect supported tokens in payment widgets (#7780) 2025-08-01 13:03:24 -07:00
MananTank e1ad7daf54 Dashboard: Remove Moralis, Alchemy API usage, Split UI improvements, Fix thirdweb/insight import (#7774)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on refactoring the wallet NFT handling and related functionalities, transitioning from using `Moralis` and `Alchemy` to utilizing `thirdweb`'s `insight`. It also includes the removal of deprecated code and updates to the types used for NFTs.

### Detailed summary
- Deleted multiple files related to `Moralis` and `Alchemy`.
- Updated the `package.json` to fix TypeScript errors for `thirdweb/insight`.
- Refactored `NFTDetails.tsx` to map `displayableNFTs` with new properties.
- Removed the `MORALIS_API_KEY` from the environment and codebase.
- Changed `useWalletNFTs` to `useOwnedNFTsInsight` for fetching NFTs.
- Updated `NFTCards.tsx` to accept a new type `OwnedNFT`.
- Modified `useSplit.ts` to fetch owned tokens using `thirdweb` instead of `Moralis`.
- Adjusted `CreateListingsForm` to use `OwnedNFT` type and updated logic accordingly.
- Updated `ContractSplitPage` to utilize `useOwnedTokenBalances` for fetching balances.
- Removed legacy handling for unsupported chains and adjusted UI components accordingly.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Unified token balance retrieval now uses Thirdweb's insight API, providing both native and ERC-20 token balances in a single view.
  * Account and contract split pages display balances in a streamlined table format, improving clarity and consistency.

* **Improvements**
  * Enhanced error handling and more informative notifications during balance distribution actions.
  * Updated logic for filtering and displaying balances, ensuring more accurate and reliable information.
  * Simplified chain support checks to rely solely on Insight API, removing Moralis and Alchemy fallbacks.
  * NFT ownership fetching now exclusively uses the Insight API with fallback to RPC data, improving reliability and simplifying support.

* **Bug Fixes**
  * Resolved inconsistencies in balance display and distribution eligibility.

* **Chores**
  * Removed deprecated Moralis and Alchemy NFT and token balance integrations.
  * Updated internal type configurations to support new balance retrieval methods.
  * Cleaned up environment variable usage by removing obsolete API keys.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-01 01:20:30 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
6ad015effb Version Packages (#7773)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-31 17:22:00 -07:00
Joaquim VergesandGitHub b86d520f3c [SDK] Handle mobile deeplinks for WalletConnect transactions (#7775) 2025-07-31 16:01:18 -07:00
Manan TankandGitHub 2df891f380 Playground: Revamp (#7768) 2025-07-31 15:37:13 -07:00
Alec AnanianandGitHub 58787a28f3 [SDK] Fix useContractEvents persisting previous data when filters change (#7766) 2025-07-31 15:34:29 -07:00
Joaquim VergesandGitHub e4ba47bd1e [SDK] Fix decodeFunction and decodeError functions (#7767) 2025-07-31 15:33:02 -07:00
Joaquim VergesandGitHub 710ac32b2f [SDK] Add WalletConnect deep linking support (#7772) 2025-07-31 14:42:22 -07:00
gregandGitHub 6258f7429c Fix: Bridge Token Examples (#7771) 2025-07-31 13:34:14 -07:00
gregandGitHub 943cd1bbcf Chore: Payment links tracking (#7769) 2025-07-31 12:23:59 -07:00
MananTank ed65f4cbe7 Portal: Move Chat UI in floating widget (#7765)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on enhancing the chat functionality in the application by introducing a new `ChatButton` component, improving code structure, and refining the chat interface with better loading states and animations.

### Detailed summary
- Removed the `Button` component linking to `/chat` in favor of `ChatButton`.
- Introduced `ChatButton` component with modal functionality for the chat interface.
- Added a `QueryClientProvider` to manage chat state.
- Improved conditional rendering and loading states in chat messages.
- Enhanced CSS animations for chat components.
- Updated key usage in `CodeClient` mapping to ensure unique keys.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Introduced a new "Ask AI" button that opens a modal chat interface, accessible across the portal.
  * The chat modal includes options to reset the conversation and close the modal, with a loading spinner for improved user experience.

* **Improvements**
  * Enhanced chat interface with animated message appearance and a more precise scroll-to-latest-message effect.
  * Updated code snippet rendering in authentication tabs to ensure unique keys for better performance and reliability.

* **Bug Fixes**
  * Resolved potential issues with rendering multiple code snippets for the same platform by ensuring unique keys.

* **Refactor**
  * Replaced previous "Ask AI" button implementations with the new unified ChatButton component for consistency.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-30 22:22:35 +00:00
MananTank 0483776825 [BLD-26] Portal: AI Chat UI improvements (#7764)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on enhancing the UI components and improving the styling, particularly around the `ScrollShadow` component. It also introduces new animations and adjusts various layouts for better responsiveness.

### Detailed summary
- Removed `ScrollShadow.tsx` and its CSS module.
- Updated color in `NextTopLoader` from `--link-foreground` to `--foreground`.
- Added `sonner` package for toasts.
- Integrated `ScrollShadow` in multiple components.
- Adjusted layout styles in `page.tsx` and `MarkdownRenderer.tsx`.
- Enhanced `Chat` component with `ScrollShadow` for better scrolling behavior.
- Introduced `TextShimmer` and `UnderlineLink` components.
- Improved styling and responsiveness in various components.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Introduced a shimmering text effect for loading states.
  * Added a customizable toast notification system with theme support.
  * Added an underlined link component for consistent link styling.

* **Enhancements**
  * Refined chat interface with improved empty state, message rendering, feedback handling, and visual distinction between user and AI messages.
  * Updated markdown rendering for improved link, heading, list, and paragraph styles.
  * Improved icon rendering with unique ID management and monochrome support.
  * Adjusted chat page and loader bar styling for better layout and color consistency.

* **Bug Fixes**
  * Corrected React key usage in code snippet rendering to use unique platform IDs.

* **Refactor**
  * Modularized chat message rendering and feedback logic.
  * Updated import paths for scroll shadow components across multiple files.

* **Chores**
  * Updated dependencies to include the "sonner" package.
  * Cleaned up whitespace, formatting, and removed unused lint comments.
  * Adjusted Tailwind configuration for border radius and added shimmer animation.

* **Removals**
  * Deleted legacy scroll shadow component and associated CSS.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-30 19:18:10 +00:00
MananTank cd142f9ff5 [BLD-28] Dashboard: Fix error style in contract explorer (#7763)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the error display section within the `InteractiveAbiFunction` component to enhance readability and styling.

### Detailed summary
- Removed the import of `InlineCode`.
- Changed the error display from a fragment (`<>`) to a `div`.
- Updated the error heading to include a bottom margin (`mb-2`).
- Replaced `InlineCode` with `PlainTextCodeBlock` for error formatting.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Style**
  * Updated the visual appearance of error messages in the interactive ABI function section for improved readability, using a new code block style with enhanced formatting.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-30 19:01:16 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
cfea3b39ee Version Packages (#7762)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-30 03:22:48 -07:00
Joaquim VergesandGitHub d35b6fc1fe Fix CheckoutWidget transaction invalidation and NFT filtering in connect UI (#7761) 2025-07-30 03:16:04 -07:00
Joaquim VergesandGitHub bcb3b92397 [Docs] Update import path in encodeAbiParameters example (#7760) 2025-07-30 02:18:28 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
be803185aa Version Packages (#7754)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-29 16:43:35 -07:00
Joaquim VergesandGitHub ea247dbd4c [Dashboard] Add FTUX completion tracking for Engine checklist (#7758) 2025-07-29 16:30:47 -07:00
MananTank e8470fcce1 Log SIWA escalation failure error message (#7740)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing error handling in the `createSupportTicket` function within the `support.ts` file. It ensures that even if the feedback submission fails, the ticket creation process continues without interruption.

### Detailed summary
- Changed the variable `res` to store the result of the `fetch` call to the SIWA URL.
- Added an error handling block to log an error message if the `fetch` response is not OK, without failing the ticket creation process.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved error handling for support ticket escalation, ensuring errors are logged if escalation fails without interrupting ticket creation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-29 23:02:35 +00:00
MananTank a6483f4a80 Playground: Rename account-abstraction page slugs (#7756)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating routing paths in the application to reflect new endpoints for account abstraction features. It changes the hrefs for specific wallet routes and adds new rewrite rules in the configuration.

### Detailed summary
- Updated `href` for the `sponsor` route to `/wallets/account-abstraction/eip-4337`.
- Updated `href` for the `7702` route to `/wallets/account-abstraction/eip-7702`.
- Updated `href` for the `5792` route to `/wallets/account-abstraction/eip-5792`.
- Added new rewrite rules in `next.config.mjs` for the updated routes.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Updated sidebar links for account abstraction wallets to use explicit EIP-prefixed paths for improved clarity.

* **Chores**
  * Added redirects to ensure legacy account abstraction wallet URLs automatically forward to the new EIP-prefixed paths.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-29 19:50:26 +00:00
MananTank 2e901123c4 Dashboard: Completely remove Chakra UI (#7755)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on removing the `@chakra-ui/react` library and its related components from the project, transitioning to a custom UI implementation.

### Detailed summary
- Deleted multiple `chakra` components and utility files.
- Removed `ChakraProviderSetup` usage from various components.
- Updated styles and layout in the `ContractPageLayout` and `ContractSplitPage`.
- Modified ESLint rules to disable chakra-specific restrictions.
- Updated `package.json` and `pnpm-lock.yaml` to remove `@chakra-ui` dependencies.

> The following files were skipped due to too many changes: `pnpm-lock.yaml`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 18:16:01 +00:00
MananTank 5c5b910570 Dashboard: migrate sponsorship policies from chakra to tailwind (#7753)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `AccountAbstractionSettingsPage` component to improve its structure and replace Chakra UI components with custom UI components, enhancing maintainability and consistency.

### Detailed summary
- Removed `ChakraProviderSetup` wrapper.
- Replaced Chakra UI components with custom components (e.g., `Button`, `Form`, `Input`, `Textarea`, `Select`, `Switch`).
- Introduced `DynamicHeight` for responsive form sections.
- Updated form handling to use custom `FormField` component for better organization.
- Enhanced the layout and styling of sponsorship policies and admin accounts sections.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 18:16:00 +00:00
MananTank 6b9f29d43c Dashboard: Migrate contract/settings page from chakra to tailwind (#7752)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `ContractSettingsPage` and its components to improve code structure and readability. It introduces a new UI library for forms and enhances the user experience with better layout and error handling.

### Detailed summary
- Refactored `ContractSettingsPage` to use `div` and `cn` for layout instead of `Flex` and `GridItem`.
- Updated `ContractSettingsPageInner` to accept props directly instead of using an interface.
- Replaced `Card` and `Flex` components with `div` and new UI components for a cleaner look.
- Introduced new form components (`Form`, `FormControl`, etc.) for better organization and handling.
- Enhanced error handling for form submissions with toast notifications.
- Updated styling for a more modern UI approach across all settings components.
- Simplified the logic for rendering settings components based on their support status.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 18:16:00 +00:00
MananTank fad7cb92b7 Dashboard: migrate contract/proposals from chakra to tailwind (#7751)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances the `DelegateButton` and `ProposalButton` components in a proposal management interface. It improves error handling, updates UI components, and modifies the structure of the `ContractProposalsPage` to enhance user experience and maintainability.

### Detailed summary
- Added `parseError` utility for improved error handling.
- Updated `DelegateButton` to show success/error messages using `toast`.
- Refactored `ContractProposalsPage` to use a cleaner layout with improved proposal handling.
- Enhanced `ProposalButton` with a new form structure and error messages.
- Updated `Proposal` component to use new UI elements like `Badge` and `CardContent`.
- Improved voting feedback by displaying vote counts and statuses more clearly.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 18:16:00 +00:00
MananTank 03617047e2 Dashboard: Migrate contract/permissions page from chakra to tailwind, UI improvements (#7750)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `Permissions` component and related files by improving UI elements, restructuring code for clarity, and integrating better user feedback mechanisms such as alerts and toast notifications.

### Detailed summary
- Updated the `Permissions` component's return structure to include headings and descriptions.
- Refined the `alertVariants` in `alert.tsx` for better styling.
- Replaced `ButtonGroup` with a `div` for layout adjustments in the `Permissions` component.
- Enhanced error handling with toast notifications in `permissions-editor.tsx`.
- Improved form handling and cleaned up values before submission.
- Replaced `DelayedDisplay` with an `Alert` component in `permissions-editor.tsx`.
- Updated the `ContractPermission` component to utilize `Select` for role management instead of traditional dropdowns.
- Added conditional rendering for alerts based on role states in `ContractPermission`.
- Adjusted button styles and behavior for better user experience across components.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 18:16:00 +00:00
MananTank 04c7243994 Dashboard: Migrate various components from chakra to tailwind #2 (#7749)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring components for better structure and performance, particularly in the forms and tables related to NFTs. It also removes unused components and improves the user experience with updated UI elements and error handling.

### Detailed summary
- Removed `FormHelperText` and `FormErrorMessage` from `chakra/form`.
- Refactored `NFTSharedMetadataButton` to use a function component instead of a React.FC.
- Updated `ContractPermissionsPage` to use a function component and improved prop handling.
- Replaced `FormControl` and `FormErrorMessage` with a new form structure in `NFTRevealButton`.
- Refactored `SharedMetadataForm` to enhance form handling and error messaging.
- Updated `NFTGetAllTable` to streamline pagination and data fetching logic.
- Removed unused imports and components to clean up the codebase.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Refactor**
  * Updated multiple NFT dashboard components to use a new custom UI library, replacing Chakra UI and simplifying form and table logic.
  * Improved form validation and error handling with integrated schema validation and toast notifications.
  * Streamlined table rendering and pagination for NFT listings with a more explicit and user-friendly approach.
  * Simplified permission and metadata management pages for improved clarity and consistency.

* **Chores**
  * Removed deprecated Chakra UI-based components and helper utilities, including custom link and button components no longer in use.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-29 18:15:59 +00:00
MananTank 66cba857dc Dashboard: Migrate various components from chakra to tailwind (#7743)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on refactoring and enhancing forms in various components by replacing `@chakra-ui/react` form elements with a custom UI form system. It also introduces new validation schemas using `zod` for improved form handling and user feedback.

### Detailed summary
- Replaced `FormControl`, `FormLabel`, and related components from `@chakra-ui/react` with custom UI components in multiple files.
- Introduced `FormFieldSetup` and `FormField` components for better form structure.
- Added `zod` validation schemas for form data validation in `ClaimTab` and `NFTClaimButton`.
- Updated form submission logic to use the new form handling approach.
- Enhanced user feedback through improved error handling and notifications.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 17:36:26 +00:00
MananTank 0426fe5c6e Dashboard: Migrate contract/events from chakra to tailwind (#7742)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR refactors the `EventsFeed` component in `events-feed.tsx`, updating its structure and styling while changing the imported UI components to a custom design system. It enhances the user interface and maintains the same functionality.

### Detailed summary
- Replaced Chakra UI components with custom components from the UI library.
- Modified the `EventsFeed` component to use `function` syntax instead of `React.FC`.
- Updated the layout from `Flex` and `SimpleGrid` to `div` with Tailwind CSS classes.
- Changed event selection handling to use `Select` from the custom library.
- Refined the `EventsFeedItem` component structure and styling.
- Updated the way transaction data is displayed with `CopyTextButton`.
- Adjusted the accordion implementation to use custom `Accordion` components.
- Removed unused imports and props for cleaner code.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 17:36:26 +00:00
MananTank 542360cc69 Dashboard: Migrate contract/account from chakra to tailwind (#7741)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the UI and refactoring components in the dashboard, specifically in the `account` section. It improves the display of error messages, balances, and NFT ownership, while also updating component structures for better readability and maintainability.

### Detailed summary
- Updated error messages in `nfts-owned.tsx` with improved styling.
- Refactored `AccountBalance` to use props directly and changed layout to a grid.
- Simplified the `AccountPage` component, enhancing readability and structure.
- Refactored `DepositNative` to streamline props and improve input handling.
- Enhanced `AccountSigner` layout for better visual presentation and clarity.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-29 17:36:25 +00:00
MananTank 5e883ac550 Dashboard: Migrate contract/accounts page from chakra to tailwind (#7739)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring components in the `accounts` section of the dashboard, enhancing code structure and UI elements while removing deprecated features.

### Detailed summary
- Deleted the `accounts-count.tsx` file.
- Removed `Legacy_CopyButton` and its usage.
- Updated `AccountsPage` to use `UnderlineLink` and improved layout.
- Refactored `CreateAccountButton` to streamline props handling.
- Replaced `TWTable` with custom table components in `AccountsTable`.
- Added pagination functionality and improved loading states.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Refactor**
  * Simplified the Accounts page layout and styling by switching from Chakra UI to Tailwind CSS.
  * Streamlined the AccountsTable with a new table design, fixed page size, and updated pagination controls.
  * Updated Create Account button with unified styling, improved labeling, and a new icon.
  * Removed the accounts count display from the page.
  * Updated external documentation link and link styling for clarity.
  * Removed legacy copy button component and related clipboard functionality.

* **Style**
  * Improved visual consistency with updated button and table styles.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-29 17:36:25 +00:00
gregandGitHub c717eaadae [SDK] Feature: Faster payment widget quote generation (#7745) 2025-07-29 10:07:01 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
691b7e1454 Version Packages (#7747)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-28 20:46:34 -07:00
Joaquim VergesandGitHub 243749b08c [Docs] Update README with comprehensive SDK package information (#7738) 2025-07-28 20:46:21 -07:00
Joaquim VergesandGitHub 4f38198ae1 [SDK] Improve WalletConnect connection and auto-connection flow (#7746) 2025-07-28 20:31:36 -07:00
MananTank b371bf9630 Dashboard: Published Contract page UI improvements, Fix audit link (#7735)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the handling of IPFS URLs, enhancing the user interface, and refactoring components for better readability and maintainability. It includes updates to various components and functions to streamline the codebase and improve functionality.

### Detailed summary
- Changed `shortenString` default parameter from `true` to `false`.
- Updated `SelectTrigger` to have a `w-fit` class.
- Replaced `replaceIpfsUrl` with `publicIPFSGateway` and `resolveSchemeWithErrorHandler` in multiple components.
- Modified `ContractFunctionsOverview` to remove `onlyFunctions` prop.
- Updated UI elements for consistency and better spacing.
- Refactored `PublisherHeader` to `PublisherLink` for clarity.
- Enhanced `PublishedContract` component layout and structure.
- Added account address handling in multiple components.
- Improved error handling and logging in IPFS URL resolution.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an "Edit" button to contract headers, visible only to the publisher when viewing their own contract.
  * Publisher information is now displayed with a more compact and streamlined UI.

* **UI Improvements**
  * Enhanced styling for contract headings, buttons, and function panels for better readability and consistency.
  * Updated publisher and contract layouts for improved clarity and usability.
  * Improved tab logic and feedback in contract function panels, including clearer "No inputs required" messaging.
  * Adjusted layout widths and border styles for published contract pages.
  * Refined link styling and layout in platform fee information sections.
  * Modified version selector width behavior for better fit.

* **Bug Fixes**
  * Updated IPFS URL handling for images and links, ensuring more reliable and consistent resolution.

* **Refactor**
  * Simplified and consolidated publisher and contract components for maintainability.
  * Replaced or removed deprecated utility functions for URL resolution.
  * Streamlined function panel logic and removed unnecessary props.
  * Refactored publisher header component to a more compact link-based design.

* **Chores**
  * Updated internal utility defaults (e.g., string shortening behavior) to improve display consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-28 18:49:17 +00:00
Joaquim VergesandGitHub cf401bee84 [Dashboard] Add thirdweb API option alongside Engine API (#7734) 2025-07-27 21:08:03 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
c178d3ab2b Version Packages (#7733)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-27 18:53:00 -07:00
Joaquim VergesandGitHub e92d8f921a Update insight, add contract filtering (#7710) 2025-07-27 18:43:42 -07:00
Joaquim VergesandGitHub 1cbbbc3c12 [SDK] Add EIP-5792 support to Coinbase and refactor wallet capabilities (#7732) 2025-07-27 18:27:22 -07:00
Joaquim VergesandGitHub 58dbe90b93 [SDK] Fallback to onchain nonce in 7702 execution (#7729) 2025-07-27 17:47:38 -07:00
MananTank 0c6d75dfc6 Dashboard: Migrate Claim condition components from chakra to tailwind, UI improvements (#7731)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the user interface and functionality of the claim conditions forms in the dashboard application. It includes updates to component structures, styling improvements, and the introduction of new features for better user experience.

### Detailed summary
- Removed unused CSV files from the assets.
- Updated `variant` prop in `tx-button` to include "outline".
- Adjusted styles in `drop-zone` for improved layout.
- Enhanced text styles in `price-preview` and `claim-conditions` components.
- Replaced `CustomFormControl` with `FormFieldSetup` for better form handling.
- Added new components for displaying and managing claim conditions.
- Improved error handling and user feedback in various input components.
- Refactored `ClaimPriceInput` and other input components to streamline functionality.
- Introduced a new `SnapshotDataTable` for better display of CSV data.
- Enhanced snapshot upload functionality with clearer requirements and examples.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added support for an "outline" button style variant in transaction buttons.

* **Refactor**
  * Replaced Chakra UI components with a custom UI library and Tailwind CSS across claim conditions forms and related components.
  * Simplified and reorganized the layout of claim conditions phases, downloadable code blocks, and snapshot upload views for improved clarity and usability.
  * Updated CSV upload and data table experience with enhanced error display and a new code example download feature.

* **Style**
  * Improved spacing, typography, and overall visual consistency throughout claim conditions and related dashboard components.

* **Chores**
  * Removed unused or redundant components and files related to previous form controls and CSV tables.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-28 00:06:30 +00:00
MananTank 11d9f3e513 Dashboard: Migrate marketplace contract pages from chakra to tailwind (#7730)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the UI components and their functionality in the dashboard application, particularly around NFT listings, by enhancing type safety, optimizing rendering, and updating UI elements for better usability.

### Detailed summary
- Made `image_url` optional in `getWalletNFTs.ts`.
- Updated button styles and sizes in `list-button.tsx`.
- Enhanced `CurrencySelector` component with better class management.
- Refactored `ContractDirectListingsPage` and `ContractEnglishAuctionsPage` to use `props`.
- Improved `ListingDrawer` layout and added table components for better data presentation.
- Refined `MarketplaceTable` to handle pagination and data fetching more efficiently.
- Updated listing forms to use new UI components and improved validation.
- Enhanced error handling and loading states across various components.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Enhanced currency selector with an icon-based back button and improved styling flexibility.

* **Refactor**
  * Migrated marketplace listing forms and tables to a new custom UI component library for a more consistent and modern interface.
  * Simplified and streamlined marketplace table and drawer components, removing legacy dependencies and improving layout.
  * Updated listing and auction pages to delegate call-to-action buttons for better composability.
  * Improved listing details drawer with a structured table layout and clearer asset information.

* **Bug Fixes**
  * Improved handling of missing NFT images to prevent errors when image URLs are unavailable.

* **Style**
  * Updated button and icon styles for a more polished user experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-27 22:56:58 +00:00
MananTank c7fab9f5dd Dashboard: Migrate Published Contract page from chakra to tailwind, UI improvements (#7728)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the UI components and structure of the published contract pages in the dashboard. It enhances layouts, updates component props, and modifies styles for better user experience and consistency.

### Detailed summary
- Updated `version-selector` styles.
- Modified `PublishedContractBreadcrumbs` to accept `className` prop.
- Simplified `PublishedContractLayout` by returning only `props.children`.
- Refactored `DeployFormForUri` to remove `ChakraProviderSetup`.
- Enhanced `ExplorePage` layout and styles.
- Changed icons in `PublishedActions` and updated button structure.
- Improved `DeployContractInfo` layout and styles.
- Updated `MarkdownRenderer` styles for better spacing and alignment.
- Refactored `PublishedContract` to use `className` prop for styling.
- Added `PublishedContractBreadcrumbs` to multiple pages for better navigation.
- Improved `PublisherHeader` layout and styling.
- Removed unused imports and cleaned up code.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added breadcrumb navigation to published contract and deploy pages for improved navigation clarity.

* **Refactor**
  * Replaced Chakra UI components with Tailwind CSS for more consistent styling and layout across published contract pages.
  * Simplified and reorganized contract detail and publisher header layouts for better readability and usability.
  * Updated contract info display to use an enhanced image component with fallback support.

* **Style**
  * Adjusted spacing, borders, and typography for headings, lists, and paragraphs in Markdown rendering.
  * Refined button and icon styles for contract actions and links.
  * Improved overall page structure and container consistency.

* **Bug Fixes**
  * Enhanced fallback behavior for contract images when unavailable.

* **Chores**
  * Removed unused sharing utility and related "Share" button from contract actions.
  * Cleaned up unused Chakra UI imports and wrappers.

* **Documentation**
  * No user-facing documentation changes included.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-27 19:27:11 +00:00
MananTank 882ed8348b Dashboard: Migrate engine/relayers page from chakra to tailwind, remove chakra provider from engine layout (#7724)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring components related to relayers in a blockchain dashboard application, improving the user interface and functionality of forms, modals, and data handling for adding, editing, and removing relayers.

### Detailed summary
- Removed `preventOpenOnFocus` prop from several components.
- Updated `WalletAddress` component to streamline address handling.
- Refactored `AddRelayerButton` and `EditModal` to use new dialog components.
- Enhanced form validation using `zod` for relayer forms.
- Improved UI with consistent styling and layout adjustments.
- Updated `RelayersTable` to use new UI components and improved address display.
- Added error handling and success notifications for relayer actions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-27 12:22:30 +00:00
MananTank 0386638cbd Dashboard: Migrate engine/overview from chakra to tailwind (#7723)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring UI components and improving the user experience in the wallet management section of a dashboard application. It includes updates to modals, button components, and form handling while ensuring better accessibility and responsiveness.

### Detailed summary
- Updated `create-backend-wallet-button.tsx` to modify button styles and add `tabIndex` for accessibility.
- Enhanced tooltip functionality in `tooltip.tsx`.
- Added `react-qrcode-logo` dependency for QR code generation.
- Refactored `transaction-timeline.tsx` to improve transaction display and interaction.
- Converted Chakra UI modals to custom dialog components for consistency.
- Updated `transactions-table.tsx` to streamline transaction details display and manage state more effectively.
- Refined backend wallet management in `backend-wallets-table.tsx`, replacing Chakra components with custom UI elements.
- Improved form handling using `react-hook-form` and validation with `zod` in wallet-related modals.
- Enhanced user feedback through toast notifications for actions like sending funds and deleting wallets.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-27 12:22:29 +00:00
MananTank a00b7fa425 Dashboard: Migrate engine/metrics from chakra to tailwind (#7722)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the layout and user interface of the `Healthcheck` and `EngineSystemMetrics` components in the dashboard. It enhances responsiveness and readability, while also introducing new loading states and alert messages.

### Detailed summary
- Changed layout from row to column in `engine-contract-subscription.tsx`.
- Added `tracking-tight` class to the `h2` header for better text spacing.
- Refactored `Healthcheck` component to use a new loading indicator.
- Updated `EngineSystemMetrics` to use `GenericLoadingPage` instead of `Spinner`.
- Introduced `Alert` component for error messaging in `EngineSystemMetrics`.
- Replaced `Card` components with divs for layout consistency.
- Created a new `MetricRow` component for displaying metrics in a structured format.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-27 17:40:35 +05:30
Joaquim VergesandGitHub b33073875f [Docs] Remove POST method from MCP server URL (#7727) 2025-07-27 00:13:05 -07:00
Joaquim VergesandGitHub 8ddf37861c [Docs] Update MCP authentication from headers to query parameters (#7726) 2025-07-27 16:31:22 +12:00
Joaquim VergesandGitHub 34067c05d0 [Docs] Update MCP server URLs and reorder usage sections (#7725) 2025-07-26 15:46:34 -07:00
MananTank 67abd0db5b Dashboard: Migrate engine/contract-submissions from chakra to tailwind (#7721)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `EngineContractSubscriptions` and `ContractSubscriptionTable` components to improve their structure, style, and functionality. It also enhances the user experience by updating UI elements and integrating new components.

### Detailed summary
- Updated `className` in the `input` component to use `selection:bg-inverted`.
- Refactored `EngineContractSubscriptions` to use `div` instead of `Flex` for layout.
- Integrated `UnderlineLink` for better link styling.
- Changed `Switch` component's props from `isChecked` to `checked` and `onChange` to `onCheckedChange`.
- Replaced `Flex` with `div` for various elements to improve layout consistency.
- Enhanced `ContractSubscriptionTable` with new styling and improved event handling.
- Updated modal components to use `Dialog` instead of `Modal`.
- Improved error handling and user notifications using `toast` for actions like adding and removing subscriptions.
- Refactored form handling with `react-hook-form` and `zod` for validation.
- Updated `FilterSelector` to use `MultiSelect` for better user interaction.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Improved contract subscription management with a redesigned multi-step form, enhanced validation, and more user-friendly filtering controls.
  * Updated contract subscriptions table with improved modals and tooltips for better usability.

* **Refactor**
  * Replaced Chakra UI components with a custom UI library for dialogs, forms, tables, tooltips, and switches.
  * Enhanced visual styling using Tailwind CSS classes.
  * Streamlined error notifications and form validation for a more consistent user experience.

* **Style**
  * Updated selection styling for input fields to improve appearance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-26 19:15:41 +00:00
gregandGitHub 6e2f535bfa [Dashboard] Payment Links Page (#7706) 2025-07-25 15:42:04 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
430115cf2b Version Packages (#7719)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-25 13:33:10 -07:00
Jonas DanielsandGitHub 80c6b6a793 Add gateway team capabilities (#7718) 2025-07-25 13:26:17 -07:00
MananTank eb2d49c4e6 Dashboard: Migrate engine/webhooks page from chakra to tailwind (#7717)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the webhook components in the dashboard application. It improves the code structure, updates UI components, and enhances the form handling for creating and managing webhooks.

### Detailed summary
- Changed `CreateWebhookInput` type definition.
- Refactored `EngineWebhooks` component to simplify props handling.
- Updated UI components in `EngineWebhooks` for better styling.
- Replaced Chakra UI modal with custom dialog components in `AddWebhookButton`.
- Enhanced form validation using `zod` in `AddWebhookButton`.
- Refactored `WebhooksTable` component for improved UI and functionality.
- Replaced modals with dialogs for delete and test webhook actions.
- Improved error handling and user notifications with `toast`.
- Updated event type selection and input handling in forms.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Refactor**
  * Updated webhooks-related components to use a custom UI library instead of Chakra UI, resulting in a more consistent interface.
  * Improved form validation and inline error messages when adding webhooks.
  * Enhanced dialog and modal interactions for adding, deleting, and testing webhooks with better state management.
  * Updated table and tooltip styling for better readability and user experience.
  * Adjusted button states and feedback to clearly indicate loading and error conditions.
  * Improved external links with enhanced security attributes and streamlined layout for webhook management.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-26 00:54:59 +05:30
jnsdls 2996121187 Update credit purchase terminology in billing section (#7705)
# Update Credit Balance Section UI

This PR updates the UI text in the credit balance section to improve clarity:

- Changed "Top Up Credits" to "Credits" in the section header
- Updated tooltip text from "Only team owners can top up credits" to "Only team owners can purchase credits"
- Changed button text from "Top Up With Crypto" to "Buy Credits"

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Style**
  * Updated text labels in the credit balance section for improved clarity, including changes to headings, tooltips, and button text.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the terminology related to credit purchases in the `CreditBalanceSection` component, making it clearer for users. The changes enhance the user experience by refining the language used in the interface.

### Detailed summary
- Changed heading from `Top Up Credits` to `Credits`.
- Updated tooltip message from `Only team owners can top up credits.` to `Only team owners can purchase credits.`.
- Renamed button text from `Top Up With Crypto` to `Buy Credits`.
- Modified summary label from `Top-up amount:` to `Added credits:` in multiple places.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 18:36:10 +00:00
MananTank cd6fd9a75d Dashboard: Migrate engine/configuration page from chakra to tailwind, UI improvements (#7716)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring and improving the UI of various configuration components for the Engine dashboard, enhancing layout, styling, and user experience while updating some logic related to wallet configurations.

### Detailed summary
- Updated layout classes for `local-config.tsx`, `engine-configuration.tsx`, and `system.tsx`.
- Added `UnderlineLink` component for links in `engine-wallet-config.tsx`, `circle-config.tsx`, and others.
- Improved styling for alerts and forms in various components.
- Enhanced error handling and user feedback with toast notifications in `cors.tsx`, `ip-allowlist.tsx`, and wallet config components.
- Refactored props handling in `EngineWalletConfig`, `EngineCorsConfig`, and `EngineIpAllowlistConfig` to use inline type definitions.
- Added `SaveIcon` and `Spinner` components for better loading and saving indicators in forms.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 18:22:38 +00:00
MananTank 12c42c0311 Dashboard: Migrate engine/admins page from chakra to tailwind (#7715)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the `EngineAdmins` and `AddAdminButton` components, enhancing their structure and UI by replacing Chakra UI components with custom UI components, and improving form handling using `react-hook-form` and `zod` for validation.

### Detailed summary
- Replaced Chakra UI components with custom UI components (`UnderlineLink`, `Dialog`, `Form`, etc.).
- Refactored `EngineAdmins` to use a simpler function signature.
- Updated the layout and styling of the `EngineAdmins` component.
- Enhanced `AddAdminButton` to use `react-hook-form` for form handling and validation.
- Introduced `zod` for schema validation in `AddAdminButton`.
- Refactored modal dialogs to use the new `Dialog` component.
- Updated `AdminsTable` to manage state for editing and removing admins more effectively.
- Improved error handling and notifications using `toast` for admin actions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 18:22:38 +00:00
MananTank 5e11d63e11 Dashboard: Migrate engine/access-tokens page from chakra to tailwind (#7714)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring components in the `Engine` section of the dashboard, enhancing UI elements, and improving error handling for access tokens and keypairs management.

### Detailed summary
- Replaced `Modal` components with `Dialog` components for improved UI consistency.
- Enhanced error handling using `toast` notifications.
- Updated button components for better visual consistency.
- Refactored `AddAccessTokenButton`, `KeypairsTable`, and `AccessTokensTable` components for cleaner code.
- Simplified state management for modal visibility.
- Improved accessibility and user experience in forms and alerts.
- Updated various imports to use new UI components from the design system.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 18:22:38 +00:00
MananTank 1d6e98dafd Dashboard: Migrate publish contract components from chakra to tailwind (#7713)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the code in the `dashboard` application to improve UI components by replacing `chakra-react-select` with a custom select component, updating various forms, and enhancing the layout and styling for better usability.

### Detailed summary
- Replaced `chakra-react-select` with a custom `Select` component.
- Updated imports for UI components to use a unified path.
- Refactored `RefInputImplFieldset` to destructure props.
- Enhanced `ExternalLinksFieldset` styling and functionality.
- Improved layout and styling in `FactoryFieldset` and `NetworksFieldset`.
- Updated `AbiSelector` to use the new `Select` component.
- Modified `CustomFactory` and `LandingFieldset` for better UI consistency.
- Changed form handling and submission logic in `ContractPublishForm`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 18:22:37 +00:00
MananTank c077f78e3a Dashboard: Migrate contract deployment UI from chakra to tailwind (#7712)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the button components and form controls in the dashboard application, improving the UI consistency and structure by replacing `FormControl` with a custom `FormFieldSetup` component and adjusting button properties.

### Detailed summary
- Changed the export of `ButtonProps` in `apps/dashboard/src/chakra/button.tsx` to remove the `export` keyword.
- Updated button imports in `apps/dashboard/src/@/components/solidity-inputs/button.tsx` to use the new path.
- Modified the `IpfsUploadButton` to use `variant="secondary"` and added a `disabled` state.
- Replaced `FormControl` with `FormFieldSetup` in multiple components for better structure and error handling.
- Adjusted the props passed to `FormFieldSetup` for improved clarity and functionality.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Refactor**
  * Unified form field presentation by replacing direct Chakra UI form controls with a custom, reusable form field component across contract deployment and module configuration forms.
  * Simplified error handling, labels, and helper text management for a more consistent user experience.

* **Style**
  * Updated button styling and icon placement for IPFS upload actions, improving visual consistency and feedback during upload operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-25 18:11:53 +00:00
MananTank 6b7983f47c Dashboard: Update outdated Portal links, Portal redirect cleanup (#7699)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating various links throughout the application to direct users to the new `wallets` and `payments` sections instead of the old `connect` endpoints, improving navigation consistency.

### Detailed summary
- Updated `href` links in multiple files to point to new `wallets` and `payments` URLs.
- Changed labels for links to reflect updated navigation terminology.
- Removed deprecated links related to the old `connect` structure.
- Ensured all changes maintain the same functionality while improving user experience.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Bug Fixes**
  * Updated multiple documentation and help URLs throughout the dashboard to point to new or consolidated destinations for wallets, payments, and account abstraction features.
  * Adjusted footer and header links, as well as empty state and help links, to reflect the latest documentation structure.
  * Removed or replaced outdated links and labels for improved clarity and navigation.

* **Chores**
  * Refined and unified redirect mappings to consolidate legacy documentation paths, ensuring users are directed to the most relevant and up-to-date wallet and payment resources.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-25 12:12:19 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
859290f6c7 Version Packages (#7709)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-25 04:40:24 -07:00
Joaquim VergesandGitHub adec6be844 [SDK] Fix showQrModal option not respected on desktop web (#7711) 2025-07-25 04:34:04 -07:00
c80eed3552 [Docs] Add search and pagination to wallet list (#7703)
Co-authored-by: Cursor Agent <[email protected]>
2025-07-25 03:50:50 -07:00
Joaquim VergesandGitHub 0c7051b999 [Docs] Update API endpoints and add frontend/backend examples (#7692) 2025-07-24 19:09:42 -07:00
Joaquim VergesandGitHub 3c8e444fe6 [SDK] Fix ecosystem wallet connection with default chains (#7708) 2025-07-24 19:02:00 -07:00
MananTank 367a25ca5a Dashboard: Migrate Explorer components from chakra to tailwind (#7707)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the UI components and functionality of the `ContractExplorerPage` and related components in the dashboard by refining layout, enhancing accessibility, and optimizing code structure.

### Detailed summary
- Updated layout for `ContractExplorerPage` to enhance UI consistency.
- Improved header elements for better accessibility.
- Refined tab structure in `ContractFunctionsOverview` for better navigation.
- Enhanced styling of buttons and inputs for a more modern look.
- Replaced `Card` components with simpler layouts where applicable.
- Introduced new utility functions for class name management.
- Optimized the handling of function inputs and outputs in `InteractiveAbiFunction`.
- Adjusted the rendering of function and event lists for improved clarity.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 01:13:51 +00:00
MananTank c0ffa1c871 Dashboard: Migrate Published contract > code tab from chakra to tailwind (#7704)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on improving the `CodeOverview` and `CodeSegment` components by enhancing their layouts, functionality, and structure. It introduces new sections, components, and props to better handle user interactions and display relevant information.

### Detailed summary
- Updated `className` in `CodeSegment` for better styling.
- Added `scrollableContainerClassName` prop in `CodeSegment`.
- Refactored `CodeOverview` to use props instead of interface.
- Introduced `AccentButtonListContainer` and `AccentButton` components for button lists.
- Created `AccountFactorySection` for account integration guidance.
- Enhanced tab handling and layout in `CodeOverview`.
- Improved user messaging and conditional rendering for SDK installation instructions.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-07-25 01:13:51 +00:00
MananTank 36731096b9 Dashboard: Migrate /tokens contract page from chakra to tailwind (#7695)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on improving the functionality and user experience of token management features in a dashboard application, including enhancements to file downloads, airdrop processes, and form validations.

### Detailed summary
- Removed unused `supportedERCs` from `ContractTokensPage`.
- Added redirects for unsupported ERC20 tokens.
- Improved the `LazyMintNftForm` with validation on image uploads.
- Introduced `DownloadableCode` component for code downloads.
- Added `AirdropCSVTable` for better CSV data handling.
- Enhanced `TokenAirdropForm` with improved transaction handling and notifications.
- Refactored various token management buttons to use consistent form structures and validation.
- Updated airdrop upload process to handle CSV files more effectively with user feedback.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced a new DownloadableCode component for displaying and downloading code examples.
  * Added a paginated CSV table for airdrop address and quantity previews.

* **Refactor**
  * Simplified and unified token action forms (airdrop, burn, claim, mint, transfer) with improved validation, streamlined UI, and consistent notifications.
  * Replaced custom code example components with the new DownloadableCode component across relevant views.
  * Updated CSV upload experience with clearer instructions and reusable components.
  * Improved conditional navigation for unsupported token standards.

* **Bug Fixes**
  * Enhanced form validation and error handling for token-related actions.

* **Chores**
  * Updated import paths for consistency and maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-25 01:13:51 +00:00
gregandGitHub 1607229b21 [Dashboard] Feature: New Payments Overview UI (#7702) 2025-07-24 15:22:44 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
75bf09126f Version Packages (#7701)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-24 13:40:52 -07:00
Jonas DanielsandGitHub 9d8c7f1f7d Add gateway to possible usage sources (#7700) 2025-07-24 13:39:12 -07:00
MananTank 9dc8f5a637 [TOOL-5111] Playground: Update slugs, add redirects (#7698)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on renaming and restructuring routes from `/connect` to `/wallets`, alongside adjustments in documentation links and component imports to streamline the application.

### Detailed summary
- Updated redirect paths from `/connect/...` to `/wallets/...`
- Changed documentation links accordingly
- Refactored component imports to match new route structure
- Adjusted breadcrumb links and sidebar navigation items
- Renamed files and folders to reflect the new `/wallets` hierarchy

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Expanded and reorganized URL redirects for improved navigation, including new paths for wallets, payments, and transactions sections.

* **Refactor**
  * Updated navigation links and internal references to use new URL structures for wallets, payments, and transactions.
  * Simplified import paths and component structures for improved code clarity and maintainability.

* **Documentation**
  * Updated documentation links throughout the app to reflect new URLs and more relevant resources.

* **Style**
  * Minor formatting improvements for code consistency and readability.

* **Chores**
  * Enhanced code comments to clarify the use of array index as React list keys.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-24 20:20:12 +00:00
Jonas DanielsandGitHub 48361f92b7 Add custom amount input to credit balance section (#7697) 2025-07-24 12:46:25 -07:00
MananTank 1659ae3754 Dashboard: Migrate Various forms in contract pages from chakra to tailwind (#7690)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring the form components in the dashboard's NFT management system to improve structure and usability. It replaces Chakra UI components with custom UI components, enhancing consistency and maintainability.

### Detailed summary
- Refactored `PropertiesFormControl` to utilize custom form components.
- Removed unused imports and consolidated imports from `@chakra-ui/react`.
- Updated form handling to use `FormField`, `FormItem`, and `FormDescription`.
- Enhanced error handling by integrating `FormMessage` for displaying validation messages.
- Replaced `Flex`, `FormControl`, and other Chakra UI components with custom equivalents.
- Updated `LazyMintNftForm`, `NFTMintForm`, and `UpdateNftMetadata` forms to use new structure and components.
- Improved user experience by refining button and input styles and behavior.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Migrated all NFT-related form components from Chakra UI to a custom UI library, updating form controls, buttons, accordions, and input elements.
  * Updated error handling and helper text display to use new form components.
  * Simplified and modernized form structures for minting, lazy minting, metadata updates, and property controls.
  * Removed file upload support and reset functionality from the properties form.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-24 18:49:38 +00:00
MananTank 88d44aff50 Dashboard: Migrate Batch Upload NFTs from chakra to tailwind, UI improvements (#7689)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refactoring and enhancing the `FilePreview` component, improving the upload process for NFTs, and updating various components to utilize the new structure. Several files related to example CSVs were deleted, and new features were added for better file handling.

### Detailed summary
- Deleted example CSV files.
- Added `FilePreview` import in multiple components.
- Enhanced `FilePreview` styling and functionality.
- Updated `DownloadFileButton` to accept additional props.
- Refactored `BatchTable` to improve pagination and display logic.
- Improved `UploadStep` for better user experience during file uploads.
- Introduced `DelayedRevealConfiguration` and `SelectReveal` components for managing NFT reveal types.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Refactor**
  * Replaced Chakra UI and third-party libraries with a custom UI system across batch upload components for a more unified look and feel.
  * Simplified and restyled batch minting forms, tables, upload steps, and reveal configuration.
  * Updated drag-and-drop functionality to use a dedicated DropZone component.
  * Streamlined table rendering and pagination with manual state management and local UI components.
  * Improved layout, styling, and accessibility for option selection, shuffle toggle, and modal dialogs.
  * Enhanced media preview styling and standardized file preview imports for improved consistency.
  * Added tabbed format selection and enriched instructional content with downloadable CSV/JSON examples in the upload step.
  * Improved submit button placement and added help links for user guidance during batch minting.
* **New Features**
  * Added customizable button variants and styling options to the file download button for better UI flexibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-24 18:17:47 +00:00
gregandGitHub c63b3497bd Feature: New Payments Overview Page (#7691) 2025-07-24 11:16:42 -07:00
74a21635e4 [Portal] Fix: Broken /connect Links (#7679)
Co-authored-by: Manan Tank <[email protected]>
2025-07-24 11:02:50 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
66b9bf3c6b Version Packages (#7694)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-24 02:00:52 -07:00
Joaquim VergesandGitHub cf22c23b45 [SDK] Optimize 4337 signature performance (#7693) 2025-07-24 00:47:45 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
170b020e17 Version Packages (#7682)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-23 19:25:46 -07:00
Joaquim VergesandGitHub 8260af3a92 [Dashboard] Replace modular contracts with Arbitrum Stylus contracts in explore page (#7685) 2025-07-22 19:15:42 -07:00
Joaquim VergesandGitHub b9154cc9e7 [API] Init API wrapper package (#7684) 2025-07-22 18:46:02 -07:00
Joaquim VergesandGitHub 08955f1588 [SDK] Expose getAuthToken from inApp and ecosystem wallets (#7683) 2025-07-22 18:26:46 -07:00
gregandGitHub 756295241a [SDK] Feature: Adds optional transactionId parameter to Bridge.status (#7681) 2025-07-22 15:11:04 -07:00
Joaquim VergesandGitHub 249679481e [Docs] Update redirects for wallets and payments paths (#7680) 2025-07-22 15:09:00 -07:00
Joaquim VergesandGitHub a491de4d7c [Docs] Refactor Contract and Tokens docs (#7676) 2025-07-22 17:20:00 +12:00
gregandGitHub 898efc56a9 [Portal] Fix: Test Jam Feedback (#7677) 2025-07-21 21:32:26 -07:00
c0e7ae95de Add external wallet filter and display (#7669)
Co-authored-by: Cursor Agent <[email protected]>
2025-07-21 20:39:26 -07:00
Joaquim VergesandGitHub 1e8190a1f9 [Docs] Add frontend/backend tabs for transaction sending examples (#7670) 2025-07-21 19:36:18 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
aac187a76c Version Packages (#7662)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-21 16:35:51 -07:00
Manan TankandGitHub 03390c1e25 Portal: homepage UI improvements (#7667) 2025-07-21 16:35:29 -07:00
8d3b9c6a33 [Portal] Fix: update sidebar overflow behavior in DocLayout component (#7653)
Co-authored-by: Joaquim Verges <[email protected]>
2025-07-21 14:47:24 -07:00
MananTank ddef88866f [PRO-249] Portal: Update OG images (#7664)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the metadata and image attributes across various pages in the `thirdweb` portal, particularly in the payments and vault sections. It modifies titles, icons, and descriptions to enhance clarity and consistency.

### Detailed summary
- Changed `metadata` for payments to use "payments" icon and updated titles.
- Updated vault metadata to include a new image with the "vault" icon.
- Modified various page descriptions for clarity and consistency.
- Added a new script for formatting in `package.json`.
- Removed unused code in `api/og/route.tsx`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added and updated metadata images and titles across several pages, including "Contracts", "Vault", and various "Payments" pages for improved visual representation.
  * Introduced support for a new "vault" icon in metadata image options.

* **Style**
  * Improved formatting and removed extraneous blank lines in code examples and UI components for better readability.
  * Cleaned up whitespace in multiple example code snippets.

* **Chores**
  * Added a new formatting script for consistent code style across the project.

* **Refactor**
  * Simplified Open Graph image layouts by removing certain UI elements.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-21 20:42:32 +00:00
Manan TankandGitHub 8133fab9e4 [TOOL-5083] Portal: Fix header on mobile viewport (#7661) 2025-07-21 13:41:30 -07:00
Joaquim VergesandGitHub 37414eb54a [SDK] Fix native token fallback when insight query fails (#7666) 2025-07-21 13:39:29 -07:00
MananTank 22bf68a6f0 [TOOL-5075] SDK: Fix various alignment issues in components (#7657)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on fixing various alignment issues in React components within the `thirdweb` package, enhancing hover states and visual consistency across different UI elements.

### Detailed summary
- Updated hover styles in several components to improve visual feedback.
- Adjusted `all` property to "unset" for better styling control.
- Modified colors and borders in `OTPLoginUI.tsx`, `ReceiveFunds.tsx`, `DepositScreen.tsx`, and others for consistency.
- Enhanced button styles in `MenuButton.tsx`, `WalletEntryButton.tsx`, and `NetworkSelector.tsx`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Resolved various alignment issues in React components to improve visual consistency across the interface.

* **Chores**
  * Updated internal documentation to reflect the latest patch addressing alignment fixes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-21 17:58:07 +00:00
EimanandGitHub 68dd4dc17e fixed playground import (#7660) 2025-07-21 10:46:58 -07:00
saminacodes ecf6dbf2aa Update portal label to TypeScript SDK (#7658)
```
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

[Portal] Fix: Update SDK title for TypeScript reference pages

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Updates the SDK title displayed on TypeScript reference pages from "Connect SDK" to "TypeScript SDK" for improved clarity and accuracy.

## How to test

Navigate to any `/references/typescript/v*/` page (e.g., `/references/typescript/v5/`). Verify the header displays "TypeScript SDK".

-->
```

---

**Open Background Agent:**
[Web](https://www.cursor.com/agents?id=bc-2dec36af-4b62-431c-b277-891c1b46bb48) · [Cursor](https://cursor.com/background-agent?bcId=bc-2dec36af-4b62-431c-b277-891c1b46bb48)

[Slack Thread](https://thirdwebdev.slack.com/archives/C04DYC3G5NZ/p1753110978408999?thread_ts=1753110978.408999&cid=C04DYC3G5NZ)

Learn more about [Background Agents](https://docs.cursor.com/background-agents)

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on renaming references from `Connect SDK` to `TypeScript SDK` and `thirdweb SDK` across multiple files in the project, enhancing clarity and consistency in the documentation and codebase.

### Detailed summary
- Updated `label` from `Connect SDKs` to `thirdweb SDKs`.
- Changed `name` from `Connect SDK` to `TypeScript SDK`.
- Modified `sdkTitle` from `Connect SDK` to `TypeScript SDK`.
- Adjusted example descriptions and titles to reflect `TypeScript SDK`.
- Updated installation instructions to refer to `TypeScript SDK`.
- Revised descriptions related to wallet support to mention `thirdweb SDKs`.
- Changed references in guides and documentation from `Connect SDK` to `TypeScript SDK`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Updated SDK naming from "Connect SDK" to "TypeScript SDK" and "thirdweb SDK" across documentation, guides, UI labels, and sidebar links for improved clarity and consistency.

* **Chores**
  * Removed the "Engine" API link from the main navigation header.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-21 16:52:47 +00:00
Phillip HoandGitHub 01daaceb21 only one file (#7659) 2025-07-21 23:23:18 +08:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
a5345808ec Version Packages (#7640)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-21 02:22:54 -07:00
Joaquim VergesandGitHub bfa0a42219 [SDK] Fix TransactionWidget when wallet has enough currency (#7656) 2025-07-21 02:13:17 -07:00
426bb8bbb2 [SDK] Fix: fixes auto-connect on native <ConnectEmbed /> component (#7650)
Co-authored-by: Joaquim Verges <[email protected]>
2025-07-20 18:09:51 -07:00
823af013ae [SDK] Fix: update hooks to use core transaction types (#7647)
Co-authored-by: Joaquim Verges <[email protected]>
2025-07-20 18:02:09 -07:00
gregandGitHub 98aea1e0b9 [Portal] Payments Docs (#7651) 2025-07-20 17:46:20 -07:00
Joaquim VergesandGitHub 620e294f8c [Engine] Update server wallet config types for EOA and EIP-7702 execution (#7652) 2025-07-20 17:43:13 -07:00
Joaquim VergesandGitHub 84eaded152 [Dashboard] Show EOA server wallets by default (#7645) 2025-07-20 16:26:55 -07:00
MananTank 31d7173432 Dashboard: Show upsell card on support page for free plan (#7648)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances the support functionality within the dashboard, particularly for teams on a free billing plan. It adds checks for the billing plan, modifies the `SupportHeader`, and integrates upsell content to encourage users to upgrade their plans.

### Detailed summary
- `SupportHeader` now accepts `isFreePlan` prop to conditionally render buttons.
- Redirects free plan users from creating support cases.
- Displays upsell content for free plan users in the support page.
- Added functionality to show/hide support forms based on billing plan.
- Updated `CreateSupportCase` component to handle dialog state for support case creation.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Free plan users now see an upsell prompt encouraging upgrade to access the Support Center, with a clear list of benefits.
  * The Support Center title has been updated for improved clarity.
  * Support case creation is disabled for free plan users, showing an informative message with a billing link instead.
  * Conditional support action buttons are shown only for paid plans, adapting to the user's context.

* **Improvements**
  * Enhanced visual styling and layout for benefit descriptions in upsell prompts.
  * Error messages in the Support Center now display detailed information for easier troubleshooting.
  * Dialogs for creating support cases now open and close with explicit user control for better interaction.
  * The chat button is hidden on the Support Center page to reduce UI clutter.

* **Bug Fixes**
  * Free plan users are prevented from accessing the support case creation page.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-18 21:17:54 +00:00
Yash094 a48329b697 [dashboard] - support in dashboard (#7608)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on restructuring the support ticketing system by moving components and modifying links to streamline support interactions within the application.

### Detailed summary
- Deleted multiple support-related files and components.
- Changed `getTeamById` function to remove the `export` keyword.
- Updated support links to point to `/team/~/~/support`.
- Added new support ticket types and forms.
- Introduced new components for handling support tickets.
- Implemented ticket status handling and filtering.
- Enhanced the support case list display with filtering options.
- Created API endpoints for support ticket management.
- Integrated dynamic imports for various support forms.

> The following files were skipped due to too many changes: `apps/dashboard/src/@/components/chat/CustomChatContent.tsx`, `apps/dashboard/src/@/components/chat/CustomChats.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/SupportCaseDetails.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/support/_components/CreateSupportCase.tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Unified support ticket system integrated into team dashboards with AI chat assistant and dynamic product-specific support forms.
  * Support ticket listing with status filtering, search, detailed conversation views, and reply functionality.
  * Added "Support" link in team sidebar footer; updated support headers, layouts, and navigation flows.
  * Introduced monochrome mode for mini logo and refined chat UI elements.

* **Bug Fixes / Improvements**
  * Enhanced chat component styling and user experience.
  * Removed obsolete "Support" links from navigation menus and headers.
  * Updated button labels, including changing "Ask AI Assistant" to "Get Help".

* **Chores**
  * Removed legacy support ticket creation pages, components, and client/server logic to consolidate support workflows.
  * Cleaned deprecated components, imports, redirects, and updated error messages to point to the new support section.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-18 19:09:16 +00:00
Joaquim VergesandGitHub 6e62a3aa5c [Docs] Add Ecosystem Wallet to sidebar and update documentation (#7643) 2025-07-18 16:47:56 +12:00
Jonas DanielsandGitHub 746b0c9d8b Add mcp to team capabilities (#7636) 2025-07-17 17:46:55 -07:00
gregandGitHub 0f38a1287a [SDK] Feature: Hide the TransactionWidget contract label if unknown (#7642) 2025-07-17 16:32:05 -07:00
gregandGitHub 61bfebf5d8 Chore: Use /search route for routes page (#7639) 2025-07-17 13:40:29 -07:00
170c377445 Handle token balance retrieval failures (#7600)
Co-authored-by: Cursor Agent <[email protected]>
2025-07-17 13:40:15 -07:00
Yash094 4cbf67181d Add etherlink chain (#7634)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces new blockchain definitions for the Etherlink mainnet and testnet, enhancing the `thirdweb` package with additional chain support.

### Detailed summary
- Added `etherlink` mainnet definition in `packages/thirdweb/src/chains/chain-definitions/etherlink.ts`.
- Added `etherlinkTestnet` definition in `packages/thirdweb/src/chains/chain-definitions/etherlink-testnet.ts`.
- Exported `etherlink` and `etherlinkTestnet` in `packages/thirdweb/src/exports/chains.ts`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added support for the Etherlink mainnet and Etherlink testnet blockchain networks.
  * Users can now interact with these new chains within the platform.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-17 19:24:21 +00:00
arcoraven 6bf6108beb chore: webhooks docs (#7604)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces a new `Webhooks` section in the application, providing a sidebar navigation item, a dedicated layout, and detailed documentation on webhooks, including their configuration, management, and security practices.

### Detailed summary
- Added `sidebar` configuration for `Webhooks` in `sidebar.tsx`.
- Introduced `SDKCard` for `Webhooks` in `page.tsx`.
- Renamed `BAST_URL` to `BASE_URL` in `metadata.ts`.
- Created a new `Layout` component for `Webhooks` in `layout.tsx`.
- Defined metadata for `Webhooks` in `layout.tsx`.
- Added comprehensive documentation for webhooks in `page.mdx`, covering setup, management, event handling, and security.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced a new "Webhooks" section in the backend APIs grid, accessible from the main portal.
  * Added comprehensive documentation for thirdweb Webhooks, including setup, management, security, and troubleshooting guides.
  * Implemented a dedicated sidebar and layout for the Webhooks documentation page for easier navigation.

* **Documentation**
  * Provided detailed instructions and code examples for implementing and verifying webhook integrations.

* **Bug Fixes**
  * Corrected a typo in the base URL constant used for metadata generation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-17 19:12:38 +00:00
Phillip HoandGitHub ce85be3346 chore: accordion, rename insight topic, test webhook endpoint (#7635) 2025-07-17 20:57:22 +08:00
MananTank e125e743a3 Dashboard: Temporarily remove gas sponsorship option in token creation (#7631)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on temporarily disabling the gasless feature in two components: `launch-token.tsx` and `launch-nft.tsx`. The condition for enabling gasless functionality has been commented out and replaced with a static `false` value.

### Detailed summary
- In `launch-token.tsx`:
  - `canEnableGasless` is set to `false` with a comment about enabling it later.
  - `showGaslessSection` is set to `false`.

- In `launch-nft.tsx`:
  - `canEnableGasless` is set to `false` with a comment about enabling it later.
  - `showGaslessSection` is set to `false`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * The gasless transaction feature and related UI have been temporarily disabled for both NFT and token launch flows.

* **Chores**
  * Updated internal logic to prevent access to the gasless sponsorship section until further notice.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-16 17:35:01 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
05da842b7a Version Packages (#7616)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-16 10:14:03 -07:00
MananTank 216b70475e Dashboard, Portal, Playground: Rename leftover usage of 'Universal Bridge' to 'Payments' in UI (#7611)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on renaming references from `Universal Bridge` to `Payments` across various files in the codebase, reflecting a rebranding initiative.

### Detailed summary
- Changed `name` and `title` from `Universal Bridge` to `Payments` in multiple files.
- Updated labels and descriptions in UI components to reflect the new branding.
- Modified sidebar links and metadata to align with the new `Payments` terminology.
- Adjusted documentation references to `Payments` from `Universal Bridge`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **Style**
  * Updated all user-facing references of "Universal Bridge" to "Payments" across banners, page titles, headings, navigation links, sidebars, and documentation content for a consistent branding experience.

* **Documentation**
  * Revised documentation text, metadata, and quickstart guides to reflect the new "Payments" terminology and branding.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-16 16:20:48 +00:00
iuwqyir 9d259d0836 add insight filter selection to webhook creation and update (#7598)
<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on enhancing the webhook configuration components by introducing optional support for `ThirdwebClient` and `supportedChainIds`. It improves error handling and validation, particularly in the context of filtering for event and transaction webhooks.

### Detailed summary
- Made `thirdwebClient` optional in `useAbiProcessing` hook.
- Updated `CreateWebhookConfigModal`, `EditWebhookConfigModal`, `WebhooksOverview` to accept `client` and `supportedChainIds`.
- Enhanced error handling in `useQuery` for missing `thirdwebClient`.
- Introduced separate forms for event and transaction filters in `TopicSelectorModal`.
- Improved validation and fetching of ABIs in the filter forms.
- Added support for displaying ABI fetch status and results.
- Enhanced UI elements to accommodate new filter configurations.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Enhanced webhook topic selection with advanced, form-driven filtering for contract webhook topics, including multi-network and ABI-based options.
  * Added support for passing client and supported chain information throughout the webhooks dashboard for improved filtering and configuration.

* **Improvements**
  * Increased dialog width for filter configuration to improve usability.
  * Streamlined handling of webhook topic filters for consistency and flexibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-16 13:17:01 +00:00
Phillip HoandGitHub ca52cdd3bf chore: /token and /vault landing pages (#7633) 2025-07-16 20:26:13 +08:00
Joaquim VergesandGitHub cf68002922 [Docs] Update page.mdx (#7632)
Signed-off-by: Joaquim Verges <[email protected]>
2025-07-16 02:08:40 -07:00
MananTank 495c7f925d [TOOL-5047] Dashboard: Fix client object missing teamId on contract publish page (#7628)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `PublishContractPage` component to utilize the `getUserThirdwebClient` function for client initialization, enhancing user authentication handling during contract publishing.

### Detailed summary
- Added import for `getUserThirdwebClient` from `@/api/auth-token`.
- Removed import for `getClientThirdwebClient` from `@/constants/thirdweb-client.client`.
- Replaced the client initialization in `ContractPublishForm` with `userThirdwebClient` from `getUserThirdwebClient`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Updated the way the client is obtained for the contract publish form, improving consistency in client retrieval. No visible changes to user experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-15 20:09:58 +00:00
iuwqyir 32add5f602 Display webhook secret in dashboard (#7610)
```
<!--

## title your PR with this format: "[Dashboard] Feature: Display and Mask Webhook Secret in Contracts Webhooks List"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):
INFRA-1524

## Notes for the reviewer

This PR introduces a new column to the Contracts Webhooks table to display the `webhook_secret`.

Key points:
- The secret is masked for security, showing `**********` followed by the last 3 characters (e.g., `**********xyz`).
- The full secret can be copied to the clipboard using the adjacent copy button.
- No backend changes were required as the `webhook_secret` is already available in the `WebhookResponse`.

## How to test

1. Navigate to a project's webhooks page on the dashboard (`/dashboard/[team_slug]/[project_slug]/webhooks`).
2. Observe the new "Webhook Secret" column in the table.
3. Verify that the secrets are displayed in the masked format (`**********xyz`).
4. Click the copy icon next to a masked secret and confirm that the full secret is copied to your clipboard.

-->
```

---

[Slack Thread](https://thirdwebdev.slack.com/archives/C085X0VQCF3/p1752487882125419?thread_ts=1752487882.125419&cid=C085X0VQCF3)

<!-- start pr-codex -->

---

## PR-Codex overview
This PR introduces a new function to mask webhook secrets for improved security and updates the `WebhooksTable` component to display the masked secret while allowing users to copy the original secret.

### Detailed summary
- Added `maskWebhookSecret` function to mask webhook secrets.
- Updated `WebhooksTable` to include a new column for "Webhook Secret."
- Displayed masked secret in the table with an option to copy the original secret.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added a new "Webhook Secret" column to the webhooks table, displaying masked webhook secrets for improved privacy.
  * Included a copy button to easily copy the full unmasked webhook secret to the clipboard.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-15 19:59:09 +00:00
gregandGitHub 5f74b3ca3e Chore: Update UB jsdocs to include types (#7629) 2025-07-15 11:50:42 -07:00
GiselleNessi 761cde6a32 [portal] add new support article (#7595)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `knowledge-base` section by adding new assets and a comprehensive guide for bulk updating NFT metadata, specifically for ERC-721A contracts.

### Detailed summary
- Added multiple image assets to the `knowledge-base`.
- Introduced a new guide in `page.mdx` for bulk updating NFT metadata.
- Explained concepts of batch and base URI in the context of NFTs.
- Provided step-by-step instructions for updating NFT metadata efficiently.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added a new sidebar entry for "Bulk update NFT metadata" under the "Contracts" section in the Troubleshoot category.
  * Introduced a comprehensive step-by-step guide on how to update metadata for multiple NFTs in bulk, including instructions, images, and helpful resources.

* **Documentation**
  * Expanded the knowledge base with detailed troubleshooting documentation for bulk updating NFT metadata.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-15 16:55:09 +00:00
Joaquim VergesandGitHub 9546b927d9 [Docs] Redesign sidebar and update wallet documentation (#7602) 2025-07-15 01:26:32 -07:00
jnsdls f82f885dad Update nebula rateLimit type to include perSecond and perMinute (#7614)
# Update Nebula Rate Limit Type

This PR updates the Nebula rate limit type to provide more granular control by replacing the single `rateLimit` number with an object containing `perSecond` and `perMinute` properties. The change affects:

- The `TeamCapabilities` type in the service-utils package
- Corresponding mock data and stubs in the dashboard app
- Added a changeset to document this patch update
2025-07-15 00:12:41 +00:00
jnsdls 34d2fddf49 Update error response URL for project settings (#7613)
# Update error response URL in service-utils

This PR updates the error response URLs in the service-utils package to point to the project-specific settings page instead of the generic API key creation page. The new URLs follow the format `https://thirdweb.com/${team.slug}/${project.slug}/settings`, providing users with a direct link to manage restrictions for their specific project.

The changes affect error messages for:
- Unauthorized domains
- Unauthorized bundle IDs
- Unauthorized services
- Unauthorized service actions

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Updated error messages for unauthorized access to provide project-specific URLs, directing users to the relevant project settings page for more accurate guidance.

* **Chores**
  * Added documentation to track the patch update related to error response URLs.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-15 00:12:41 +00:00
a7544f75ce [Portal] Add next button to inner page footers (#7605)
Co-authored-by: Cursor Agent <[email protected]>
2025-07-14 15:46:21 -07:00
gregandGitHub bd3d645be6 [SDK] Fix: Adds BuyWidget fallback when native isn't supported (#7601) 2025-07-14 12:06:18 -07:00
MananTank 5fedc2c040 [TOOL-5037] Dashboard: Remove autoConnect on /login page (#7609)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on refactoring import paths for better organization and consistency across the codebase, as well as enhancing the login and onboarding components, including UI adjustments and functionality updates.

### Detailed summary
- Updated import paths to use absolute imports instead of relative paths.
- Modified the `DashboardLayout` to enable auto-connect.
- Enhanced the `LoginPage` with a new footer message regarding phone login support.
- Adjusted the `Toaster` component to simplify its usage.
- Improved onboarding UI components for better user experience.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added an option to enable automatic wallet connection in the app layout.

* **Refactor**
  * Standardized import paths across the dashboard for improved maintainability and clarity.
  * Updated usage of the notification component to a local version with simplified theming.
  * Improved layout and messaging on the login page, moving phone login deprecation notice to a dedicated footer and refining spacing.

* **Documentation**
  * Enhanced SEO and social sharing metadata on the login page.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-14 18:36:51 +00:00
Yash094 6c8a7cf2ba fix playground payments widget (#7607)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `CodeGen` component in the `playground-web` application by renaming a prop for consistency and clarity.

### Detailed summary
- Changed the prop name from `token` to `tokenAddress` in the `CodeGen` component.
- Maintained existing conditional rendering for other props such as `seller`, `title`, `image`, `description`, `paymentMethods`, and `currency`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Updated the generated code output to use the prop name `tokenAddress` instead of `token` when displaying the token address in the code example. This change does not affect any other visible functionality.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-14 18:01:58 +00:00
Phillip HoandGitHub 4f02f6eeb7 chore: add webhook secret to table, fix api error (#7606) 2025-07-14 15:55:21 +08:00
72f75ea40b Update converter SDK reference (#7603)
Co-authored-by: Cursor Agent <[email protected]>
2025-07-14 12:53:52 +08:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
8b6a953933 Version Packages (#7594)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-13 10:27:06 +12:00
Joaquim VergesandGitHub 33b0b6dcb4 [Dashboard] Add server-wallet signAuthorization capability to wallet access token (#7530) 2025-07-12 02:53:53 -07:00
MananTank cdc7d95db2 [TOOL-4959] Dashboard: Asset page UI improvements (#7599)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on refining the UI components and enhancing the functionality of the `ERC20` public page. It includes improvements in layout, styling, and the introduction of new features related to token price data and analytics.

### Detailed summary
- Deleted unused files: `useTokenPriceData.ts` and `ContractCreatorBadge.tsx`.
- Updated `PageHeader` to change border style.
- Added `tooltip` prop in `CopyAddressButton`.
- Changed API key usage in `fetchTokenInfoFromBridge`.
- Enhanced `ThirdwebAreaChart` with better props handling.
- Introduced `GridPattern` component for background.
- Improved `RecentTransfers` UI and pagination buttons.
- Updated `PriceChart` and `TokenStats` to directly use passed props for token price data.
- Refactored `ContractHeaderUI` to improve layout and social link handling.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Introduced a customizable grid background pattern component for enhanced visual design.
  * Added support for displaying token price data and analytics on ERC20 public pages, including conditional rendering of token statistics.
  * Enabled tooltip customization for the copy address button.

* **Bug Fixes**
  * The contract creator badge icon is now visible, and spacing between elements has been improved.

* **Refactor**
  * Simplified and unified chart headers and analytics section layouts.
  * Streamlined fetching and handling of token price data with a new asynchronous function and removed the previous hook.
  * Improved layout and container styling across ERC20 and NFT public pages, including card backgrounds, borders, and spacing.
  * Adjusted component structures for better visual separation and consistency.
  * Removed the contract creator badge component and replaced it with a simpler contract owner link.

* **Style**
  * Updated card and header styles for better visual hierarchy and clarity.
  * Enhanced recent transfers and contract header sections with improved padding, borders, and rounded corners.
  * Removed small shadow effects from cards and refined header background and border styles.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-12 05:50:29 +05:30
Manan TankandGitHub 592bf6f1fd [TOOL-5021] SDK: Fix theme in ConnectButton Details Modal Buy screen (#7589) 2025-07-12 09:21:50 +12:00
MananTank 8973174ad5 Dashboard: Fix erc20 asset page crash when number of tokens claimed is a fraction (#7597)
<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on updating the `SupplyClaimedProgress` component to use `claimedSupplyTokens` and `totalSupplyTokens` as `number` types instead of `bigint`, along with minor adjustments in related components and UI elements.

### Detailed summary
- Changed `enable-background` to `enableBackground` in `DiscordIcon.tsx`.
- Updated `SupplyClaimedProgress` props from `claimedSupply` and `totalSupply` (bigint) to `claimedSupplyTokens` and `totalSupplyTokens` (number).
- Adjusted calculations and conditions in `SupplyClaimedProgress` for new props.
- Modified test cases in stories to reflect new prop types.
- Updated UI elements to display supply values correctly based on the new number type.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Refactor**
  * Updated supply progress components and related usage to use number types instead of bigints, with new prop names for clarity.
  * Improved handling and display of "unlimited" supply scenarios in supply progress components.
  * Adjusted percentage calculation and formatting for claimed supply progress.

* **Style**
  * Corrected SVG attribute naming in the Discord icon to ensure proper rendering.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-11 20:38:47 +00:00
Phillip HoandGitHub c160e91c08 chore: redirect /universal-bridge -> /payments (#7593) 2025-07-12 04:20:58 +08:00
gregandGitHub f33e31ad6e [SDK] Fix: only require missing token amount for transaction widget (#7591) 2025-07-11 02:01:57 -07:00
Joaquim VergesandGitHub 4111d0e638 [Dashboard] Add error handling and refactor vault account rotation (#7592) 2025-07-10 19:59:42 -07:00
joaquim-verges ffb7b6487b [Dashboard] use BuyWidget on /bridge (#7590)
Fixes TOOL-5023

<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the `UniversalBridgeEmbed` component to replace the `PayEmbed` with `BuyWidget` from the `thirdweb` library, modifying how payment options are handled and improving the integration with the `thirdweb` SDK.

### Detailed summary
- Replaced `PayEmbed` component with `BuyWidget`.
- Removed `payOptions` prop and its nested properties.
- Added `amount`, `chain`, and `tokenAddress` props to `BuyWidget`.
- Updated the theme handling to use `getSDKTheme`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Updated the embedded widget in the dashboard to use a new buy widget, offering a simplified and more direct interface for purchasing tokens.

* **Refactor**
  * Streamlined the widget’s input options for a more straightforward user experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-10 23:09:34 +00:00
2040 changed files with 90616 additions and 44772 deletions
+142 -28
View File
@@ -15,37 +15,150 @@
<p align="center"><strong>All-in-one web3 SDK for Browser, Node and Mobile apps</strong></p>
## Features
## Core Package
- Support for React & React-Native
- First party support for [Embedded Wallets](https://portal.thirdweb.com/connect/embedded-wallet/overview) (social/email login)
- First party support for [Account Abstraction](https://portal.thirdweb.com/connect/account-abstraction/overview)
- Instant connection to any chain with RPC Edge integration
- Integrated IPFS upload/download
- UI Components for connection, transactions, nft rendering
- High level contract extensions for interacting with common standards
#### [`thirdweb`](./packages/thirdweb/README.md)
The main SDK package providing all-in-one web3 functionality for Browser, Node, and Mobile applications.
```bash
npm install thirdweb
```
**Features:**
- Type-safe contract and transaction APIs
- In-app wallets with social/email login
- Account abstraction (ERC4337/EIP7702) support
- 500+ external wallets supported
- Built in infra (RPC, bundler, paymaster, indexer)
- React hooks and UI components
- Automatic ABI resolution
- IPFS upload/download
- Cross-platform support (Web, React Native)
## Library Comparison
### Documentation
| | thirdweb | Wagmi + Viem | Ethers@6 |
| ----------------------------------------- | -------- | ------------------ | -------- |
| Type safe contract API | ✅ | ✅ | ✅ |
| Type safe wallet API | ✅ | ✅ | ✅ |
| EVM utils | ✅ | ✅ | ✅ |
| RPC for any EVM | ✅  | ⚠️ public RPC only | ❌ |
| Automatic ABI Resolution | ✅ | ❌ | ❌ |
| IPFS Upload/Download | ✅ | ❌ | ❌ |
| Embedded wallet (email/ social login) | ✅ | ⚠️ via 3rd party | ❌ |
| Account abstraction (ERC4337) support | ✅ | ⚠️ via 3rd party | ❌ |
| Web3 wallet connectors | ✅ | ✅ | ❌ |
| Local wallet creation | ✅ | ✅ | ✅ |
| Auth (SIWE) | ✅ | ✅ | ❌ |
| Extensions functions for common standards | ✅ | ✅ | ❌ |
| React Hooks | ✅ | ✅ | ❌ |
| React UI components | ✅ | ❌ | ❌ |
| React Native Hooks | ✅ | ✅ | ❌ |
| React Native UI Components | ✅ | ❌ | ❌ |
Visit the [developer portal](https://portal.thirdweb.com) for full documentation.
### 🚀 Quick Start
#### For React Applications
```bash
npm install thirdweb
```
```typescript
import { createThirdwebClient } from "thirdweb";
import { ConnectButton, useActiveAccount } from "thirdweb/react";
const client = createThirdwebClient({
clientId: "YOUR_CLIENT_ID",
});
function App() {
const account = useActiveAccount();
console.log("Connected as", account?.address);
return <ConnectButton client={client} />;
}
```
For React Native Applications, you'll also need to install the `@thirdweb-dev/react-native-adapter` package and import it at app startup for polyfills.
#### For Backend Applications
```bash
npm install thirdweb
```
```typescript
import { createThirdwebClient, Engine } from "thirdweb";
const client = createThirdwebClient({
secretKey: "YOUR_SECRET_KEY",
});
const wallet = Engine.serverWallet({
client,
address: "0x...",
});
const transaction = transfer({
contract: getContract({
client,
address: "0x...", // token contract
chain: defineChain(1),
}),
to: "0x...", // recipient
amount: "0.01", // amount in tokens
});
await wallet.enqueueTransaction({
transaction,
});
```
## Adapters
#### [`@thirdweb-dev/react-native-adapter`](./packages/react-native-adapter/README.md)
Required polyfills and configuration for running the thirdweb SDK in React Native applications.
```bash
npm install @thirdweb-dev/react-native-adapter
```
#### [`@thirdweb-dev/wagmi-adapter`](./packages/wagmi-adapter/README.md)
Integration layer for using thirdweb's in-app wallets with wagmi.
```bash
npm install @thirdweb-dev/wagmi-adapter
```
## Type safe API wrappers
#### [`@thirdweb-dev/api`](./packages/api/README.md)
TypeScript SDK for thirdweb's API, combining all of thirdweb products.
```bash
npm install @thirdweb-dev/api
```
#### [`@thirdweb-dev/engine`](./packages/engine/README.md)
TypeScript SDK for Engine, thirdweb's backend onchain executor service.
```bash
npm install @thirdweb-dev/engine
```
#### [`@thirdweb-dev/insight`](./packages/insight/README.md)
TypeScript SDK for Insight, thirdweb's multichain indexer service.
```bash
npm install @thirdweb-dev/insight
```
#### [`@thirdweb-dev/vault-sdk`](./packages/vault-sdk/README.md)
SDK for interacting with Vault, thirdweb's secure key management service.
```bash
npm install @thirdweb-dev/vault-sdk
```
#### [`@thirdweb-dev/nebula`](./packages/nebula/README.md)
TypeScript SDK for Nebula, thirdweb's AI agent service.
```bash
npm install @thirdweb-dev/nebula
```
## Contributing
@@ -55,7 +168,8 @@ See our [open source page](https://thirdweb.com/open-source) for more informatio
## Additional Resources
- [Documentation](https://portal.thirdweb.com/typescript/v5)
- [Dashboard](https://thirdweb.com/login)
- [Documentation](https://portal.thirdweb.com/)
- [Templates](https://thirdweb.com/templates)
- [YouTube](https://www.youtube.com/c/thirdweb)
+20 -54
View File
@@ -1,29 +1,22 @@
#
# Public (client)
#
# API authorized domain
# not required to build, defaults to prod
NEXT_PUBLIC_THIRDWEB_DOMAIN="localhost:3000"
# ------------------------------------------------------------------------
# API host. For local development, please use "https://api.thirdweb-dev.com"
# otherwise: "https://api.thirdweb.com"
# local host - http://127.0.0.1:3005
NEXT_PUBLIC_THIRDWEB_API_HOST="https://api.thirdweb-dev.com"
# Bridge API. For local development, please use "https://bridge.thirdweb-dev.com"
# otherwise: "https://bridge.thirdweb.com"
NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST="https://bridge.thirdweb-dev.com"
# Paper API host
# in-app wallet host
NEXT_PUBLIC_THIRDWEB_EWS_API_HOST="https://ews.thirdweb-dev.com"
# thirdweb local api host
# NEXT_PUBLIC_THIRDWEB_API_HOST="http://127.0.0.1:3005"
# Client ID
# Get the client id from https://thirdweb.com/create-api-key and set it here,
# Client ID - Required
# Get the client id from https://thirdweb.com/create-api-key and set it here, and also set DASHBOARD_SECRET_KEY below
# make sure to allow localhost:3000 in the allowed origins
NEXT_PUBLIC_DASHBOARD_CLIENT_ID="<replace_me_with_your_client_id>"
NEXT_PUBLIC_DASHBOARD_CLIENT_ID=""
# IPFS gateway url
NEXT_PUBLIC_IPFS_GATEWAY_URL="https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}"
@@ -39,62 +32,35 @@ NEXT_PUBLIC_TYPESENSE_CONTRACT_API_KEY=
# - not required for prod/staging
NEXT_PUBLIC_POSTHOG_KEY=""
# Stripe Customer portal
NEXT_PUBLIC_STRIPE_KEY=
# required for server wallet management
NEXT_PUBLIC_THIRDWEB_VAULT_URL=""
NEXT_PUBLIC_ENGINE_CLOUD_URL=""
# Demo Engine - required for showing demo engine page
NEXT_PUBLIC_DEMO_ENGINE_URL=""
NEXT_PUBLIC_STRIPE_PAYMENT_METHOD_CFG_ID=
#
# Private (server)
#
# Get the secret key from https://thirdweb.com/create-api-key and set it here, Make sure to allow localhost:3000 in the allowed origins
# ------------------------------------------------------------------------
# Get the secret key from https://thirdweb.com/create-api-key and set it here and also set NEXT_PUBLIC_DASHBOARD_CLIENT_ID above,
# Make sure to allow localhost:3000 in the allowed origins
DASHBOARD_SECRET_KEY="<replace_me_with_your_secret_key>"
# Client id for api routes
# Client id for api routes - required for contract OG image generation
API_ROUTES_CLIENT_ID=
# <moralis.io API key (used for api routes for token balances and wallet NFTs)
# - not required to build (unless using wallet NFTs and token balances)>
MORALIS_API_KEY=
# alchemy.com API key (used for wallet NFTS)
# - cannot be restricted to IP/domain because vercel has no stable IPs and it happens during build & runtime api route call
# - not required to build (unless testing wallet NFTs)>
SSR_ALCHEMY_KEY=
# Hubspot Access Token (used for contact us form)
# - not required to build (unless testing contact us form)>
HUBSPOT_ACCESS_TOKEN=
# Upload server url
NEXT_PUBLIC_DASHBOARD_UPLOAD_SERVER="https://storage.thirdweb-preview.com"
# Unthread variables - only required for submitting the support form in /support
UNTHREAD_API_KEY=""
UNTHREAD_TRIAGE_CHANNEL_ID=""
UNTHREAD_EMAIL_INBOX_ID=""
UNTHREAD_FREE_TIER_ID=""
UNTHREAD_GROWTH_TIER_ID=""
UNTHREAD_PRO_TIER_ID=""
# Demo Engine
NEXT_PUBLIC_DEMO_ENGINE_URL=""
# API server secret (required for thirdweb.com SIWE login). Copy from Vercel.
API_SERVER_SECRET=""
# Used for the Faucet page (/<chain_id>)
# Used in faucet on chain page (/<chain-id>) and login page (/login) - turnstile is disabled in localhost development
NEXT_PUBLIC_TURNSTILE_SITE_KEY=""
TURNSTILE_SECRET_KEY=""
REDIS_URL=""
ANALYTICS_SERVICE_URL=""
# required for billing parts of the dashboard (team -> settings -> billing / invoices)
STRIPE_SECRET_KEY=""
# required for server wallet management
NEXT_PUBLIC_THIRDWEB_VAULT_URL=""
NEXT_PUBLIC_ENGINE_CLOUD_URL=""
+6 -61
View File
@@ -10,13 +10,6 @@ module.exports = {
"plugin:storybook/recommended",
],
overrides: [
// disable restricted imports in chakra
{
files: "src/chakra/**/*",
rules: {
"no-restricted-imports": ["off"],
},
},
// allow direct PostHog imports inside analytics helpers
{
files: "src/@/analytics/**/*",
@@ -91,60 +84,6 @@ module.exports = {
"error",
{
paths: [
{
// these are provided by chakra folder, so we don't want to import them from chakra directly
importNames: [
"Card",
"Button",
"Checkbox",
"Badge",
"Drawer",
"Heading",
"Text",
"FormLabel",
"FormHelperText",
"FormErrorMessage",
"MenuGroup",
"VStack",
"HStack",
"AspectRatio",
"useToast",
"useClipboard",
"Badge",
"Stack",
// also the types
"ButtonProps",
"BadgeProps",
"DrawerProps",
"HeadingProps",
"TextProps",
"FormLabelProps",
"HelpTextProps",
"MenuGroupProps",
"MenuItemProps",
"AspectRatioProps",
"BadgeProps",
"StackProps",
],
message:
'import component from "chakra" folder instead if you have to use chakra component, But use shadcn component otherwise',
name: "@chakra-ui/react",
},
{
message:
"Import from `@chakra-ui/react` instead of `@chakra-ui/layout`.",
name: "@chakra-ui/layout",
},
{
message:
"Import from `@chakra-ui/react` instead of `@chakra-ui/button`.",
name: "@chakra-ui/button",
},
{
message:
"Import from `@chakra-ui/react` instead of `@chakra-ui/menu`.",
name: "@chakra-ui/menu",
},
{
importNames: ["useRouter"],
message:
@@ -157,6 +96,12 @@ module.exports = {
name: "posthog-js",
},
],
patterns: [
{
group: ["**/../@/**"],
message: "Use absolute imports instead. Example: '@/foo/bar..'",
},
],
},
],
"no-restricted-syntax": [
-5
View File
@@ -20,11 +20,6 @@ const config: StorybookConfig = {
name: getAbsolutePath("@storybook/nextjs"),
options: {},
},
refs: {
"@chakra-ui/react": {
disable: true,
},
},
staticDirs: ["../public"],
features: {
experimentalRSC: true,
+5 -3
View File
@@ -9,7 +9,7 @@ module.exports = [
// -- build category
"/wallets",
"/account-abstraction",
"/universal-bridge",
"/payments",
"/auth",
"/in-app-wallets",
"/transactions",
@@ -21,8 +21,8 @@ module.exports = [
"/storage",
// -- end scale category
// -- nebula
"/nebula",
// -- ai
"/ai",
// -- contracts
"/contracts",
"/contracts/modular-contracts",
@@ -62,4 +62,6 @@ module.exports = [
// -- universal bridge landing pages --
"/universal-bridge-regions/:region_slug",
"/enterprise",
"/token",
"/vault",
];
+4 -1
View File
@@ -10,8 +10,11 @@
"ignoreDependencies": [
"@thirdweb-dev/service-utils",
"@thirdweb-dev/vault-sdk",
"thirdweb",
"@types/color",
"fast-xml-parser"
"fast-xml-parser",
"@workspace/ui",
"tailwindcss-animate"
],
"next": true,
"project": ["src/**"]
+3 -6
View File
@@ -9,10 +9,10 @@ const ContentSecurityPolicy = `
img-src * data: blob:;
media-src * data: blob:;
object-src 'none';
style-src 'self' 'unsafe-inline' vercel.live;
style-src 'self' 'unsafe-inline' vercel.live us.posthog.com;
font-src 'self' vercel.live assets.vercel.com framerusercontent.com fonts.gstatic.com;
frame-src * data:;
script-src 'self' 'unsafe-eval' 'unsafe-inline' 'wasm-unsafe-eval' 'inline-speculation-rules' *.thirdweb.com *.thirdweb-dev.com vercel.live js.stripe.com framerusercontent.com events.framer.com challenges.cloudflare.com googletagmanager.com us-assets.i.posthog.com edit.framer.com;
script-src 'self' 'unsafe-eval' 'unsafe-inline' 'wasm-unsafe-eval' 'inline-speculation-rules' *.thirdweb.com *.thirdweb-dev.com vercel.live js.stripe.com framerusercontent.com events.framer.com challenges.cloudflare.com googletagmanager.com us-assets.i.posthog.com edit.framer.com framer.com googletagmanager.com;
connect-src * data: blob:;
worker-src 'self' blob:;
block-all-mixed-content;
@@ -115,9 +115,7 @@ const SENTRY_OPTIONS: SentryBuildOptions = {
const FRAMER_ADDITIONAL_LANGUAGES = ["es"];
const baseNextConfig: NextConfig = {
compiler: {
emotion: true,
},
transpilePackages: ["@workspace/ui"],
eslint: {
ignoreDuringBuilds: true,
},
@@ -199,7 +197,6 @@ const baseNextConfig: NextConfig = {
]),
];
},
serverExternalPackages: ["pino-pretty"],
};
function getConfig(): NextConfig {
+1 -14
View File
@@ -1,10 +1,5 @@
{
"dependencies": {
"@chakra-ui/react": "^2.8.2",
"@chakra-ui/styled-system": "^2.9.2",
"@chakra-ui/theme-tools": "^2.1.2",
"@emotion/react": "11.14.0",
"@emotion/styled": "11.14.1",
"@hookform/resolvers": "^3.9.1",
"@marsidev/react-turnstile": "^1.1.0",
"@radix-ui/react-accordion": "^1.2.11",
@@ -33,15 +28,13 @@
"@thirdweb-dev/vault-sdk": "workspace:*",
"@vercel/functions": "2.2.2",
"@vercel/og": "^0.6.8",
"@workspace/ui": "workspace:*",
"abitype": "1.0.8",
"chakra-react-select": "^4.7.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"color": "5.0.0",
"compare-versions": "^6.1.0",
"date-fns": "4.1.0",
"fast-xml-parser": "^5.2.5",
"framer-motion": "12.23.0",
"fuse.js": "7.1.0",
"input-otp": "^1.4.1",
"ioredis": "^5.6.1",
@@ -51,13 +44,11 @@
"next-themes": "^0.4.6",
"nextjs-toploader": "^1.6.12",
"nuqs": "^2.4.3",
"p-limit": "^6.2.0",
"papaparse": "^5.5.3",
"pluralize": "^8.0.0",
"posthog-js": "1.256.1",
"posthog-node": "^5.4.0",
"prettier": "3.6.2",
"qrcode": "^1.5.3",
"react": "19.1.0",
"react-children-utilities": "^2.10.0",
"react-day-picker": "^8.10.1",
@@ -86,7 +77,6 @@
},
"devDependencies": {
"@biomejs/biome": "2.0.6",
"@chakra-ui/cli": "^2.4.1",
"@chromatic-com/storybook": "4.0.1",
"@next/bundle-analyzer": "15.3.5",
"@next/eslint-plugin-next": "15.3.5",
@@ -99,7 +89,6 @@
"@types/node": "22.14.1",
"@types/papaparse": "^5.3.16",
"@types/pluralize": "^0.0.33",
"@types/qrcode": "^1.5.5",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"@types/react-table": "^7.7.20",
@@ -129,12 +118,10 @@
"dev": "next dev --turbopack",
"fix": "biome check ./src --fix && eslint ./src --fix",
"format": "biome format ./src --write",
"gen:theme-typings": "chakra-cli tokens src/chakra/theme/index.ts",
"knip": "knip",
"lint": "biome check ./src && knip && eslint ./src",
"playwright": "playwright test",
"postbuild": "next-sitemap",
"postinstall": "pnpm run gen:theme-typings",
"preinstall": "npx only-allow pnpm",
"start": "next start",
"storybook": "storybook dev -p 6006",
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
plugins: {
autoprefixer: {},
tailwindcss: {},
},
};
+1
View File
@@ -0,0 +1 @@
export { default } from "@workspace/ui/postcss.config";
@@ -1,2 +0,0 @@
name,description,image,animation_url,external_url,background_color,youtube_url,additional,properties,can be,added
Token 0 Name,Token 0 Description,ipfs://ipfsHash/0,ipfs://ipfsHash/0,https://thirdweb.com,#0098EE,,every,row,is a ,property
1 name description image animation_url external_url background_color youtube_url additional properties can be added
2 Token 0 Name Token 0 Description ipfs://ipfsHash/0 ipfs://ipfsHash/0 https://thirdweb.com #0098EE every row is a property
@@ -1,4 +0,0 @@
name,description,image,animation_url,external_url,background_color,youtube_url,additional,properties,can be,added
Token 0 Name,Token 0 Description,0.png,0.mp4,https://thirdweb.com,#0098EE,,every,row,is a ,property
Token 1 Name,Token 1 Description,0.png,0.mp4,https://thirdweb.com,#0098EE,,every,row,is a ,property
Token 2 Name,Token 2 Description,0.png,0.mp4,https://thirdweb.com,#0098EE,,every,row,is a ,property
1 name description image animation_url external_url background_color youtube_url additional properties can be added
2 Token 0 Name Token 0 Description 0.png 0.mp4 https://thirdweb.com #0098EE every row is a property
3 Token 1 Name Token 1 Description 0.png 0.mp4 https://thirdweb.com #0098EE every row is a property
4 Token 2 Name Token 2 Description 0.png 0.mp4 https://thirdweb.com #0098EE every row is a property
@@ -1,2 +0,0 @@
name,description,external_url,background_color,youtube_url,additional,properties,can be,added
Token 0 Name,Token 0 Description,https://thirdweb.com,#0098EE,,every,row,is a ,property
1 name description external_url background_color youtube_url additional properties can be added
2 Token 0 Name Token 0 Description https://thirdweb.com #0098EE every row is a property
@@ -1,3 +0,0 @@
address,maxClaimable
0x0000000000000000000000000000000000000000,2
0x000000000000000000000000000000000000dEaD,5
1 address maxClaimable
2 0x0000000000000000000000000000000000000000 2
3 0x000000000000000000000000000000000000dEaD 5
@@ -1,3 +0,0 @@
address,maxClaimable,price,currencyAddress
0x0000000000000000000000000000000000000000,2,0.1,0x0000000000000000000000000000000000000000
0x000000000000000000000000000000000000dEaD,5,2.5,0x0000000000000000000000000000000000000000
1 address maxClaimable price currencyAddress
2 0x0000000000000000000000000000000000000000 2 0.1 0x0000000000000000000000000000000000000000
3 0x000000000000000000000000000000000000dEaD 5 2.5 0x0000000000000000000000000000000000000000
@@ -1,3 +0,0 @@
address
0x0000000000000000000000000000000000000000
0x000000000000000000000000000000000000dEaD
1 address
2 0x0000000000000000000000000000000000000000
3 0x000000000000000000000000000000000000dEaD
+37 -6
View File
@@ -66,15 +66,20 @@ const projectRoute = "/team/:team_slug/:project_slug";
const projectPageRedirects = [
{
destination: `${projectRoute}/universal-bridge/:path*`,
destination: `${projectRoute}/payments/:path*`,
permanent: false,
source: `${projectRoute}/connect/pay/:path*`,
},
{
destination: `${projectRoute}/universal-bridge/:path*`,
destination: `${projectRoute}/payments/:path*`,
permanent: false,
source: `${projectRoute}/connect/universal-bridge/:path*`,
},
{
destination: `${projectRoute}/payments/:path*`,
permanent: false,
source: `${projectRoute}/universal-bridge/:path*`,
},
{
destination: `${projectRoute}/account-abstraction/:path*`,
permanent: false,
@@ -375,12 +380,22 @@ async function redirects() {
permanent: false,
source: "/template/:slug",
},
// redirect /connect/pay to /universal-bridge
// redirect /connect/pay to /payments
{
destination: "/universal-bridge",
permanent: false,
destination: "/payments",
permanent: true,
source: "/connect/pay",
},
{
destination: "/payments",
permanent: true,
source: "/universal-bridge",
},
{
destination: "/payments/:slug",
permanent: true,
source: "/universal-bridge/:slug",
},
// PREVIOUS CAMPAIGNS
{
destination: "/",
@@ -416,7 +431,7 @@ async function redirects() {
source: "/connect/account-abstraction",
},
{
destination: "/universal-bridge",
destination: "/payments",
permanent: false,
source: "/connect/universal-bridge",
},
@@ -440,9 +455,25 @@ async function redirects() {
permanent: false,
source: "/rpc-edge",
},
{
destination: "/payments",
permanent: false,
source: "/universal-bridge",
},
// redirect /nebula to /ai
{
destination: "/ai",
permanent: false,
source: "/nebula",
},
...legacyDashboardToTeamRedirects,
...projectPageRedirects,
...teamPageRedirects,
{
source: "/support/:path*",
destination: "/team/~/~/support",
permanent: false,
},
];
}
@@ -1,6 +1,6 @@
"use server";
import { getRawAccount } from "../../app/(app)/account/settings/getAccount";
import { getRawAccount } from "@/api/account/get-account";
export async function getRawAccountAction() {
return getRawAccount();
@@ -12,7 +12,7 @@ import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { API_SERVER_SECRET } from "@/constants/server-envs";
import { isVercel } from "@/utils/vercel";
import { verifyTurnstileToken } from "./verifyTurnstileToken";
import { verifyTurnstileToken } from "../../app/login/verifyTurnstileToken";
export async function getLoginPayload(
params: GenerateLoginPayloadParams,
@@ -1,89 +0,0 @@
"use server";
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 { defineDashboardChain } from "@/lib/defineDashboardChain";
type BalanceQueryResponse = Array<{
balance: string;
decimals: number;
name?: string;
symbol: string;
token_address: string;
display_balance: string;
}>;
export async function getTokenBalancesFromMoralis(params: {
contractAddress: string;
chainId: number;
}): Promise<
| { data: BalanceQueryResponse; error: undefined }
| {
data: undefined;
error: string;
}
> {
const { contractAddress, chainId } = params;
if (!isAddress(contractAddress)) {
return {
data: undefined,
error: "invalid address",
};
}
const getNativeBalance = async (): Promise<BalanceQueryResponse> => {
// eslint-disable-next-line no-restricted-syntax
const chain = defineDashboardChain(chainId, undefined);
const balance = await getWalletBalance({
address: contractAddress,
chain,
client: serverThirdwebClient,
});
return [
{
balance: balance.value.toString(),
decimals: balance.decimals,
display_balance: toTokens(balance.value, balance.decimals),
name: "Native Token",
symbol: balance.symbol,
token_address: ZERO_ADDRESS,
},
];
};
const getTokenBalances = async (): Promise<BalanceQueryResponse> => {
const _chain = encodeURIComponent(`0x${chainId?.toString(16)}`);
const _address = encodeURIComponent(contractAddress);
const tokenBalanceEndpoint = `https://deep-index.moralis.io/api/v2/${_address}/erc20?chain=${_chain}`;
const resp = await fetch(tokenBalanceEndpoint, {
headers: {
"x-api-key": MORALIS_API_KEY,
},
method: "GET",
});
if (!resp.ok) {
resp.body?.cancel();
return [];
}
const json = await resp.json();
// biome-ignore lint/suspicious/noExplicitAny: FIXME
return json.map((balance: any) => ({
...balance,
display_balance: toTokens(BigInt(balance.balance), balance.decimals),
}));
};
const [nativeBalance, tokenBalances] = await Promise.all([
getNativeBalance(),
getTokenBalances(),
]);
return {
data: [...nativeBalance, ...tokenBalances],
error: undefined,
};
}
@@ -1,210 +0,0 @@
"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";
import {
generateMoralisUrl,
transformMoralisResponseToNFT,
} 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 }
| { result?: undefined; error: string };
export async function getWalletNFTs(params: {
chainId: number;
owner: string;
isInsightSupported: boolean;
}): Promise<WalletNFTApiReturn> {
const { chainId, owner } = params;
if (params.isInsightSupported) {
const response = await getWalletNFTsFromInsight({ chainId, owner });
if (!response.ok) {
return {
error: response.error,
};
}
return { result: response.data };
}
if (isAlchemySupported(chainId)) {
const url = generateAlchemyUrl({ chainId, owner });
const response = await fetch(url, {
next: {
revalidate: 10, // cache for 10 seconds
},
});
if (response.status >= 400) {
return { error: response.statusText };
}
try {
const parsedResponse = await response.json();
const result = await transformAlchemyResponseToNFT(parsedResponse, owner);
return { error: undefined, result };
} catch (err) {
console.error("Error fetching NFTs", err);
return { error: "error parsing response" };
}
}
if (isMoralisSupported(chainId) && MORALIS_API_KEY) {
const url = generateMoralisUrl({ chainId, owner });
const response = await fetch(url, {
headers: {
"X-API-Key": MORALIS_API_KEY,
},
method: "GET",
next: {
revalidate: 10, // cache for 10 seconds
},
});
if (response.status >= 400) {
return { error: response.statusText };
}
try {
const parsedResponse = await response.json();
const result = await transformMoralisResponseToNFT(
await parsedResponse,
owner,
chainId,
);
return { result };
} catch (err) {
console.error("Error fetching NFTs", err);
return { error: "error parsing response" };
}
}
return { error: "unsupported chain" };
}
type OwnedNFTInsightResponse = {
name: string;
description: string;
image_url: string;
background_color: string;
external_url: string;
metadata_url: string;
extra_metadata: {
customImage?: string;
customAnimationUrl?: string;
animation_original_url?: string;
image_original_url?: string;
};
collection: {
name: string;
description: string;
extra_metadata: Record<string, string>;
};
contract: {
chain_id: number;
address: string;
type: "erc1155" | "erc721";
name: string;
};
owner_addresses: string[];
token_id: string;
balance: string;
token_type: "erc1155" | "erc721";
};
async function getWalletNFTsFromInsight(params: {
chainId: number;
owner: string;
}): Promise<
| {
data: WalletNFT[];
ok: true;
}
| {
ok: false;
error: string;
}
> {
const { chainId, owner } = params;
const thirdwebDomain =
getVercelEnv() === "production" ? "thirdweb" : "thirdweb-dev";
const url = new URL(`https://insight.${thirdwebDomain}.com/v1/nfts`);
url.searchParams.append("chain", chainId.toString());
url.searchParams.append("limit", "10");
url.searchParams.append("owner_address", owner);
const response = await fetch(url, {
headers: {
"x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
},
});
if (!response.ok) {
const errorMessage = await response.text();
return {
error: errorMessage,
ok: false,
};
}
const nftsResponse = (await response.json()) as {
data: OwnedNFTInsightResponse[];
};
const isDev = getVercelEnv() !== "production";
// NOTE: ipfscdn.io/ to thirdwebstorage-dev.com/ replacement is temporary
// This should be fixed in the insight dev endpoint
const walletNFTs = nftsResponse.data.map((nft) => {
const walletNFT: WalletNFT = {
chainId: nft.contract.chain_id,
contractAddress: nft.contract.address,
id: nft.token_id,
metadata: {
animation_url: isDev
? nft.extra_metadata.animation_original_url?.replace(
"ipfscdn.io/",
"thirdwebstorage-dev.com/",
)
: nft.extra_metadata.animation_original_url,
background_color: nft.background_color,
description: nft.description,
external_url: nft.external_url,
image: isDev
? nft.image_url.replace("ipfscdn.io/", "thirdwebstorage-dev.com/")
: nft.image_url,
name: nft.name,
uri: isDev
? nft.metadata_url.replace("ipfscdn.io/", "thirdwebstorage-dev.com/")
: nft.metadata_url,
},
owner: params.owner,
supply: nft.balance,
tokenAddress: nft.contract.address,
tokenURI: nft.metadata_url,
type: nft.token_type === "erc721" ? "ERC721" : "ERC1155",
};
return walletNFT;
});
return {
data: walletNFTs,
ok: true,
};
}
@@ -1,7 +1,7 @@
import "server-only";
import Stripe from "stripe";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { STRIPE_SECRET_KEY } from "@/constants/server-envs";
let existingStripe: Stripe | undefined;
@@ -5,7 +5,7 @@ import "server-only";
import { randomBytes } from "crypto";
import { format } from "date-fns";
import { getAuthToken } from "@/api/auth-token";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
export async function createTeam(options?: { name?: string; slug?: string }) {
+157 -23
View File
@@ -1,6 +1,7 @@
"use client";
import posthog from "posthog-js";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import type { ProductSKU } from "../types/billing";
// ----------------------------
@@ -223,7 +224,11 @@ export function reportChainConfigurationAdded(properties: {
// ASSETS
// ----------------------------
type AssetContractType = "DropERC20" | "DropERC1155" | "DropERC721";
type AssetContractType =
| "DropERC20"
| "DropERC1155"
| "DropERC721"
| "ERC20Asset";
/**
* ### Why do we need to report this event?
@@ -269,22 +274,6 @@ export function reportAssetBuyFailed(properties: {
// Assets Landing Page ----------------------------
/**
* ### Why do we need to report this event?
* - To track number of asset creation started from the assets page
* - To track which asset types are being created the most
*
* ### Who is responsible for this event?
* @MananTank
*/
export function reportAssetCreationStarted(properties: {
assetType: "nft" | "coin";
}) {
posthog.capture("asset creation started", {
assetType: properties.assetType,
});
}
/**
* ### Why do we need to report this event?
* - To track number of assets imported successfully from the assets page
@@ -349,6 +338,15 @@ export function reportAssetCreationSuccessful(properties: {
});
}
type CoinCreationStep =
| "erc20-asset:deploy-contract"
| "erc20-asset:airdrop-tokens"
| "erc20-asset:approve-airdrop-tokens"
| "drop-erc20:deploy-contract"
| "drop-erc20:set-claim-conditions"
| "drop-erc20:mint-tokens"
| "drop-erc20:airdrop-tokens";
/**
* ### Why do we need to report this event?
* - To track number of failed asset creations
@@ -370,11 +368,7 @@ export function reportAssetCreationFailed(
}
| {
assetType: "coin";
step:
| "deploy-contract"
| "set-claim-conditions"
| "mint-tokens"
| "airdrop-tokens";
step: CoinCreationStep;
}
),
) {
@@ -413,3 +407,143 @@ export function reportUpsellShown(properties: UpsellParams) {
export function reportUpsellClicked(properties: UpsellParams) {
posthog.capture("upsell clicked", properties);
}
// ----------------------------
// PAYMENTS
// ----------------------------
/**
* ### Why do we need to report this event?
* - To track conversions on payment overview page
*
* ### Who is responsible for this event?
* @samina
*/
export function reportPaymentCardClick(properties: { id: string }) {
posthog.capture("payment card clicked", properties);
}
/**
* ### Why do we need to report this event?
* - To create a funnel "create payment link pageview" -> "payment link created" to understand the conversion rate
*
* ### Who is responsible for this event?
* @greg
*/
export function reportPaymentLinkCreated(properties: {
linkId: string;
clientId: string;
}) {
posthog.capture("payment link created", properties);
}
/**
* ### Why do we need to report this event?
* - To track funnel "payment link pageview" -> "payment link buy successful" to understand the conversion rate
*
* ### Who is responsible for this event?
* @greg
*/
export function reportPaymentLinkBuySuccessful() {
posthog.capture("payment link buy successful");
}
/**
* ### Why do we need to report this event?
* - To track the number of failed payment link buys
* - To track what errors users encounter when trying to buy from a payment link
*
* ### Who is responsible for this event?
* @greg
*/
export function reportPaymentLinkBuyFailed(properties: {
errorMessage: string;
}) {
posthog.capture("payment link buy failed", properties);
}
/**
* ### Why do we need to report this event?
* - To create a funnel for "asset pageview" -> "asset purchase successful" to understand the conversion rate
* - To understand which asset types are being viewed the most
*
* ### Who is responsible for this event?
* @MananTank
*/
export function reportAssetPageview(properties: {
assetType: "nft" | "coin";
chainId: number;
}) {
posthog.capture("asset pageview", properties);
}
/**
* ### Why do we need to report this event?
* - To track the usage of fund wallet modal
* - To create a funnel "fund wallet modal opened" -> "fund wallet buy successful" to understand the conversion rate
*
* ### Who is responsible for this event?
* @MananTank
*/
export function reportFundWalletOpened() {
posthog.capture("fund wallet opened");
}
/**
* ### Why do we need to report this event?
* - To track the number of successful fund wallet buys
* - To create a funnel "fund wallet modal opened" -> "fund wallet buy successful" to understand the conversion rate
*
* ### Who is responsible for this event?
* @MananTank
*/
export function reportFundWalletSuccessful() {
posthog.capture("fund wallet successful");
}
/**
* ### Why do we need to report this event?
* - To track the number of failed fund wallet buys
* - To track the errors that users encounter when trying to buy from a fund wallet modal
*
* ### Who is responsible for this event?
* @MananTank
*/
export function reportFundWalletFailed(params: { errorMessage: string }) {
posthog.capture("fund wallet failed", params);
}
/**
* ### Why do we need to report this event?
* - To track the conversion rate of the users choosing to create a token from new flow instead of the old flow
*
* ### Who is responsible for this event?
* @MananTank
*/
export function reportTokenUpsellClicked(params: {
assetType: "nft" | "coin";
pageType: "explore" | "deploy-contract";
}) {
posthog.capture("token upsell clicked", params);
}
// ----------------------------
// CHAIN INFRASTRUCTURE CHECKOUT
// ----------------------------
/**
* ### Why do we need to report this event?
* - To record explicit user acknowledgement when proceeding to checkout without RPC
* - To measure how often customers choose to omit RPC while purchasing Insight and/or Account Abstraction
* - To correlate potential support issues arising from missing RPC
*
* ### Who is responsible for this event?
* @jnsdls
*/
export function reportChainInfraRpcOmissionAgreed(properties: {
chainId: number;
frequency: "monthly" | "annual";
includeInsight: boolean;
includeAccountAbstraction: boolean;
}) {
posthog.capture("chain infra checkout rpc omission agreed", properties);
}
@@ -1,8 +1,8 @@
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import type { Account } from "@/hooks/useApi";
import { getAuthToken } from "../../../../@/api/auth-token";
import { loginRedirect } from "../../login/loginRedirect";
import { isAccountOnboardingComplete } from "../../login/onboarding/isOnboardingRequired";
import { isAccountOnboardingComplete } from "@/utils/account-onboarding";
import { loginRedirect } from "@/utils/redirects";
/**
* Just get the account object without enforcing onboarding.
@@ -1,5 +1,5 @@
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { getAuthToken } from "./auth-token";
export type LinkedWallet = {
createdAt: string;
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -1,6 +1,9 @@
import { cookies } from "next/headers";
import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
import { LAST_USED_TEAM_ID } from "@/constants/cookies";
import {
COOKIE_ACTIVE_ACCOUNT,
COOKIE_PREFIX_TOKEN,
LAST_USED_TEAM_ID,
} from "@/constants/cookie";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
export async function getAuthToken() {
@@ -1,7 +1,7 @@
import type { ThirdwebClient } from "thirdweb";
import { fetchDeployMetadata as sdkFetchDeployMetadata } from "thirdweb/contract";
import { removeUndefinedFromObjectDeep } from "@/utils/object";
import type { ContractId } from "./types";
import type { ContractId } from "../../components/contract-components/types";
// metadata PRE publish, only has the compiler output info (from CLI)
@@ -0,0 +1,27 @@
import type { ThirdwebContract } from "thirdweb";
export async function verifyContract(contract: ThirdwebContract) {
try {
const response = await fetch(
"https://contract.thirdweb.com/verify/contract",
{
body: JSON.stringify({
chainId: contract.chain.id,
contractAddress: contract.address,
}),
headers: {
"Content-Type": "application/json",
},
method: "POST",
},
);
if (!response.ok) {
console.error(`Error verifying contract: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error(`Error verifying contract: ${error}`);
}
}
@@ -1,8 +1,8 @@
import {
getProjectContracts,
type ProjectContract,
} from "../../../../../@/api/getProjectContracts";
import { fetchChainWithLocalOverrides } from "../../../../../@/utils/fetchChainWithLocalOverrides";
} from "@/api/project/getProjectContracts";
import { fetchChainWithLocalOverrides } from "@/utils/fetchChainWithLocalOverrides";
export async function getSortedDeployedContracts(params: {
onlyMainnet?: boolean;
@@ -1,7 +1,7 @@
import "server-only";
import type { ProjectResponse } from "@thirdweb-dev/service-utils";
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { getAuthToken } from "./auth-token";
export type Project = ProjectResponse;
@@ -37,7 +37,7 @@ type WebhookConfigsResponse =
};
interface CreateWebhookConfigRequest {
topics: { id: string; filters: object | null }[];
topicIdsWithFilters: { id: string; filters: object | null }[];
destinationUrl: string;
description: string;
isPaused?: boolean;
@@ -76,7 +76,7 @@ type TopicsResponse =
interface UpdateWebhookConfigRequest {
destinationUrl?: string;
topics?: { id: string; filters: object | null }[];
topicIdsWithFilters?: { id: string; filters: object | null }[];
description?: string;
isPaused?: boolean;
}
@@ -310,3 +310,53 @@ export async function deleteWebhookConfig(props: {
status: "success",
};
}
type TestDestinationUrlResponse =
| {
result: {
httpStatusCode: number;
httpResponseBody: string;
};
status: "success";
}
| {
body: string;
reason: string;
status: "error";
};
export async function testDestinationUrl(props: {
teamIdOrSlug: string;
projectIdOrSlug: string;
destinationUrl: string;
}): Promise<TestDestinationUrlResponse> {
const authToken = await getAuthToken();
if (!authToken) {
return {
body: "Authentication required",
reason: "no_auth_token",
status: "error",
};
}
const resp = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${props.teamIdOrSlug}/projects/${props.projectIdOrSlug}/webhook-configs/test-destination-url`,
{
body: JSON.stringify({ destinationUrl: props.destinationUrl }),
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
method: "POST",
},
);
if (!resp.ok) {
return {
body: await resp.text(),
reason: "unknown",
status: "error",
};
}
return await resp.json();
}
@@ -1,8 +1,8 @@
"use server";
import "server-only";
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { getAuthToken } from "./auth-token";
export type AuditLogEntry = {
who: {
@@ -1,8 +1,8 @@
"use server";
import "server-only";
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { getAuthToken } from "./auth-token";
export async function createDedicatedSupportChannel(
teamIdOrSlug: string,
@@ -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 "./auth-token";
export type AuthOption =
| "email"
@@ -12,6 +12,7 @@ export type AuthOption =
| "google"
| "facebook"
| "x"
| "tiktok"
| "discord"
| "farcaster"
| "telegram"
@@ -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 { getValidAccount } from "@/api/account/get-account";
import { getAuthToken } from "@/api/auth-token";
import { LAST_USED_TEAM_ID } from "@/constants/cookie";
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 "./auth-token";
import { getMemberByAccountId } from "./team-members";
export type Team = TeamResponse & { stripeCustomerId: string | null };
@@ -48,7 +48,7 @@ export async function service_getTeamBySlug(slug: string) {
return null;
}
export function getTeamById(id: string) {
function getTeamById(id: string) {
return getTeamBySlug(id);
}
@@ -1,5 +1,5 @@
import { getAuthToken } from "@/api/auth-token";
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 { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { getAuthToken } from "./auth-token";
const TeamAccountRole = {
MEMBER: "MEMBER",
@@ -1,8 +1,8 @@
"use server";
import "server-only";
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
import { getAuthToken } from "./auth-token";
export type VerifiedDomainResponse =
| {
@@ -1,4 +1,5 @@
"use server";
import type { Address } from "thirdweb";
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST } from "@/constants/public-envs";
@@ -96,6 +97,143 @@ export async function deleteWebhook(props: {
return;
}
type PaymentLink = {
id: string;
link: string;
title: string;
imageUrl: string;
createdAt: string;
updatedAt: string;
destinationToken: {
chainId: number;
address: Address;
symbol: string;
name: string;
decimals: number;
iconUri: string;
};
receiver: Address;
amount: bigint;
};
export async function getPaymentLinks(props: {
clientId: string;
teamId: string;
}): Promise<Array<PaymentLink>> {
const authToken = await getAuthToken();
const res = await fetch(`${UB_BASE_URL}/v1/developer/links`, {
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
"x-client-id": props.clientId,
"x-team-id": props.teamId,
},
method: "GET",
});
if (!res.ok) {
const text = await res.text();
throw new Error(text);
}
const json = (await res.json()) as {
data: Array<PaymentLink & { amount: string }>;
};
return json.data.map((link) => ({
id: link.id,
link: link.link,
title: link.title,
imageUrl: link.imageUrl,
createdAt: link.createdAt,
updatedAt: link.updatedAt,
destinationToken: {
chainId: link.destinationToken.chainId,
address: link.destinationToken.address,
symbol: link.destinationToken.symbol,
name: link.destinationToken.name,
decimals: link.destinationToken.decimals,
iconUri: link.destinationToken.iconUri,
},
receiver: link.receiver,
amount: BigInt(link.amount),
}));
}
export async function createPaymentLink(props: {
clientId: string;
teamId: string;
title: string;
imageUrl?: string;
intent: {
destinationChainId: number;
destinationTokenAddress: Address;
receiver: Address;
amount: bigint;
purchaseData?: unknown;
};
}) {
const authToken = await getAuthToken();
const res = await fetch(`${UB_BASE_URL}/v1/developer/links`, {
body: JSON.stringify({
title: props.title,
imageUrl: props.imageUrl,
intent: {
destinationChainId: props.intent.destinationChainId,
destinationTokenAddress: props.intent.destinationTokenAddress,
receiver: props.intent.receiver,
amount: props.intent.amount.toString(),
purchaseData: props.intent.purchaseData,
},
}),
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
"x-client-id": props.clientId,
"x-team-id": props.teamId,
},
method: "POST",
});
if (!res.ok) {
const text = await res.text();
throw new Error(text);
}
const response = (await res.json()) as {
data: PaymentLink;
};
return response.data;
}
export async function deletePaymentLink(props: {
clientId: string;
teamId: string;
paymentLinkId: string;
}) {
const authToken = await getAuthToken();
const res = await fetch(
`${UB_BASE_URL}/v1/developer/links/${props.paymentLinkId}`,
{
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
"x-client-id": props.clientId,
"x-team-id": props.teamId,
},
method: "DELETE",
},
);
if (!res.ok) {
const text = await res.text();
throw new Error(text);
}
return;
}
export type Fee = {
feeRecipient: string;
feeBps: number;
@@ -195,30 +333,28 @@ export type Payment = {
export async function getPayments(props: {
clientId: string;
teamId: string;
paymentLinkId?: string;
limit?: number;
offset?: number;
}) {
const authToken = await getAuthToken();
// Build URL with query parameters if provided
let url = `${UB_BASE_URL}/v1/developer/payments`;
const queryParams = new URLSearchParams();
const url = new URL(`${UB_BASE_URL}/v1/developer/payments`);
if (props.limit) {
queryParams.append("limit", props.limit.toString());
url.searchParams.append("limit", props.limit.toString());
}
if (props.offset) {
queryParams.append("offset", props.offset.toString());
url.searchParams.append("offset", props.offset.toString());
}
// Append query params to URL if any exist
const queryString = queryParams.toString();
if (queryString) {
url = `${url}?${queryString}`;
if (props.paymentLinkId) {
url.searchParams.append("paymentLinkId", props.paymentLinkId);
}
const res = await fetch(url, {
const res = await fetch(url.toString(), {
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
@@ -13,12 +13,18 @@ export type TokenMetadata = {
iconUri?: string;
};
export async function getUniversalBridgeTokens(props: { chainId?: number }) {
export async function getUniversalBridgeTokens(props: {
chainId?: number;
address?: string;
}) {
const url = new URL(`${UB_BASE_URL}/v1/tokens`);
if (props.chainId) {
url.searchParams.append("chainId", String(props.chainId));
}
if (props.address) {
url.searchParams.append("tokenAddress", props.address);
}
url.searchParams.append("limit", "1000");
const res = await fetch(url.toString(), {
@@ -18,6 +18,7 @@ export function DateRangeSelector(props: {
}) {
const { range, setRange } = props;
const daysDiff = differenceInCalendarDays(range.to, range.from);
const matchingRange =
normalizeTime(range.to).getTime() === normalizeTime(new Date()).getTime()
? durationPresets.find((preset) => preset.days === daysDiff)
@@ -85,7 +86,7 @@ export function getLastNDaysRange(id: DurationId) {
throw new Error(`Invalid duration id: ${id}`);
}
const todayDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // add 1 day to avoid timezone issues
const todayDate = new Date(Date.now());
const value: Range = {
from: subDays(todayDate, durationInfo.days),
@@ -1,104 +0,0 @@
"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";
import {
DateRangeSelector,
getLastNDaysRange,
} from "@/components/analytics/date-range-selector";
import { IntervalSelector } from "@/components/analytics/interval-selector";
import { useDashboardRouter } from "@/lib/DashboardRouter";
export function RangeSelector({
range,
interval,
}: {
range?: Range;
interval: "day" | "week";
}) {
const pathname = usePathname();
const searchParams = useSearchParams();
const router = useDashboardRouter();
const [localRange, setRange] = useState<Range>(
range || getLastNDaysRange("last-120"),
);
const [localInterval, setInterval] = useState<"day" | "week">(interval);
useQuery({
queryFn: async () => {
if (range) {
setRange(range);
return range;
}
if (searchParams) {
const fromStringified = searchParams.get("from");
const from = fromStringified
? new Date(fromStringified)
: getLastNDaysRange("last-120").from;
const toStringified = searchParams.get("to");
const to = toStringified ? new Date(toStringified) : new Date();
const type = (searchParams.get("type") as DurationId) || "last-120";
setRange({ from, to, type });
setInterval(interval);
return { from, to, type } satisfies Range;
}
return getLastNDaysRange("last-120");
},
queryKey: ["analytics-range", searchParams?.toString(), range],
});
// prefetch for each interval and default range
useQuery({
queryFn: async () => {
const newSearchParams = new URLSearchParams(searchParams || {});
for (const interval of ["day", "week"] as const) {
newSearchParams.set("interval", interval);
for (const type of [
"last-120",
"last-60",
"last-30",
"last-7",
] as const) {
const newRange = getLastNDaysRange(type);
newSearchParams.set("from", newRange.from.toISOString());
newSearchParams.set("to", newRange.to.toISOString());
newSearchParams.set("type", newRange.type);
router.prefetch(`${pathname}?${newSearchParams.toString()}`);
}
}
return true;
},
queryKey: ["analytics-range", searchParams?.toString()],
});
return (
<div className="flex justify-end gap-3 flex-col lg:flex-row">
<DateRangeSelector
className="rounded-full"
range={localRange}
setRange={(newRange) => {
setRange(newRange);
const newSearchParams = new URLSearchParams(searchParams || {});
newSearchParams.set("from", newRange.from.toISOString());
newSearchParams.set("to", newRange.to.toISOString());
newSearchParams.set("type", newRange.type);
router.push(`${pathname}?${newSearchParams.toString()}`);
}}
/>
<IntervalSelector
className="bg-card rounded-full"
intervalType={localInterval}
setIntervalType={(newInterval) => {
setInterval(newInterval);
const newSearchParams = new URLSearchParams(searchParams || {});
newSearchParams.set("interval", newInterval);
router.push(`${pathname}?${newSearchParams.toString()}`);
}}
/>
</div>
);
}
@@ -0,0 +1,55 @@
"use client";
import {
useResponsiveSearchParams,
useSetResponsiveSearchParams,
} from "responsive-rsc";
import {
DateRangeSelector,
type DurationId,
} from "@/components/analytics/date-range-selector";
import { IntervalSelector } from "@/components/analytics/interval-selector";
import { getFiltersFromSearchParams, normalizeTimeISOString } from "@/lib/time";
export function ResponsiveTimeFilters(props: { defaultRange: DurationId }) {
const responsiveSearchParams = useResponsiveSearchParams();
const setResponsiveSearchParams = useSetResponsiveSearchParams();
const { range, interval } = getFiltersFromSearchParams({
defaultRange: props.defaultRange,
from: responsiveSearchParams.from,
interval: responsiveSearchParams.interval,
to: responsiveSearchParams.to,
});
return (
<div className="flex justify-end gap-3 flex-col lg:flex-row">
<DateRangeSelector
className="rounded-full"
range={range}
setRange={(newRange) => {
setResponsiveSearchParams((v) => {
const newParams = {
...v,
from: normalizeTimeISOString(newRange.from),
to: normalizeTimeISOString(newRange.to),
};
return newParams;
});
}}
/>
<IntervalSelector
className="bg-card rounded-full"
intervalType={interval}
setIntervalType={(newInterval) => {
setResponsiveSearchParams((v) => {
const newParams = {
...v,
interval: newInterval,
};
return newParams;
});
}}
/>
</div>
);
}
@@ -1,478 +0,0 @@
"use client";
import {
Alert,
AlertIcon,
Flex,
FormControl,
Input,
InputGroup,
InputRightElement,
Textarea,
} from "@chakra-ui/react";
import { zodResolver } from "@hookform/resolvers/zod";
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";
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 { 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";
type DelayedSubmit = {
revealType: "delayed";
data: CreateDelayedRevealBatchParams;
};
type InstantSubmit = {
revealType: "instant";
data: { metadatas: NFTInput[] };
};
type SubmitType = DelayedSubmit | InstantSubmit;
interface BatchLazyMintEVMProps {
nextTokenIdToMint: bigint;
canCreateDelayedRevealBatch: boolean;
onSubmit: (formData: SubmitType) => Promise<unknown>;
chainId: number;
client: ThirdwebClient;
}
type BatchLazyMintProps = BatchLazyMintEVMProps;
const BatchLazyMintFormSchema = z
.object({
confirmPassword: z
.string()
.min(1, "Please confirm your password.")
.optional(),
// metadata
metadatas: z.array(z.any()),
// delayed reveal password logic
password: z.string().min(1, "A password is required.").optional(),
// delayed reveal placeholder
placeHolder: z
.object({
description: z.string().or(z.string().length(0)).optional(),
image: z.any().optional(),
name: z.string().min(1, "A name is required"),
})
.optional(),
revealType: z.literal("instant").or(z.literal("delayed")).optional(),
// shared logic
shuffle: z.boolean().default(false),
})
.refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["confirmPassword"],
});
type BatchLazyMintFormType = z.output<typeof BatchLazyMintFormSchema> & {
metadatas: NFTInput[];
};
function useBatchLazyMintForm() {
return useForm<BatchLazyMintFormType>({
defaultValues: {
metadatas: [],
revealType: undefined,
shuffle: false,
},
resolver: zodResolver(BatchLazyMintFormSchema),
});
}
export const BatchLazyMint: ComponentWithChildren<
BatchLazyMintProps & {
isLoggedIn: boolean;
}
> = (props) => {
const [step, setStep] = useState(0);
const form = useBatchLazyMintForm();
const nftMetadatas = form.watch("metadatas");
const hasError = !!form.getFieldState("metadatas", form.formState).error;
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop: async (acceptedFiles) => {
try {
await processInputData(acceptedFiles, (data) =>
form.setValue("metadatas", data),
);
} catch {
form.setError("metadatas", {
message: "Invalid metadata files",
type: "validate",
});
}
if (nftMetadatas.length === 0) {
form.setError("metadatas", {
message: "Invalid metadata files",
type: "validate",
});
}
},
});
const paginationPortalRef = useRef<HTMLDivElement>(null);
return (
<form
className="mt-4 flex w-full flex-col"
onSubmit={form.handleSubmit((data) => {
// first shuffle
const shuffledMetadatas = data.shuffle
? shuffleData(data.metadatas)
: data.metadatas;
// check submit is instant
if (data.revealType === "instant") {
return props.onSubmit({
data: { metadatas: shuffledMetadatas },
revealType: "instant",
});
}
// validate password
if (!data.password) {
form.setError("password", {
message: "A password is required for delayed reveal.",
type: "validate",
});
return;
}
// validate placeholder
if (!data.placeHolder?.name) {
form.setError("placeHolder.name", {
message: "A name is required for delayed reveal.",
type: "validate",
});
}
// submit
return props.onSubmit({
data: {
metadata: shuffledMetadatas,
password: data.password,
placeholderMetadata: {
description: data.placeHolder?.description,
image: data.placeHolder?.image,
name: data.placeHolder?.name,
},
},
revealType: "delayed",
});
})}
>
{step === 0 ? (
<div className="flex flex-col gap-6">
{nftMetadatas.length > 0 ? (
<>
<BatchTable
client={props.client}
data={nftMetadatas}
nextTokenIdToMint={props.nextTokenIdToMint}
portalRef={paginationPortalRef}
/>
<div className="border-border border-t">
<div className="flex flex-col items-center justify-between p-0 md:flex-row md:p-4">
<div ref={paginationPortalRef} />
<div className="mt-4 flex w-full flex-row items-center gap-2 md:mt-0 md:w-auto">
<Button
borderRadius="md"
isDisabled={!hasError}
onClick={() => {
form.reset();
}}
w={{ base: "100%", md: "auto" }}
>
Reset
</Button>
<Button
borderRadius="md"
colorScheme="primary"
onClick={() => setStep(1)}
w={{ base: "100%", md: "auto" }}
>
Next
</Button>
</div>
</div>
</div>
</>
) : (
<UploadStep
getInputProps={getInputProps}
getRootProps={getRootProps}
hasFailed={hasError}
isDragActive={isDragActive}
/>
)}
</div>
) : (
<>
<Flex align="center" justify="space-between" mb={2} py={4} w="100%">
<div className="flex flex-row items-center gap-2">
<Button
className="text-muted-foreground"
onClick={() => setStep(0)}
variant="ghost"
>
<ChevronLeftIcon className="size-5 cursor-pointer" />
</Button>
<Heading className="my-auto" size="title.md">
When will you reveal your NFTs?
</Heading>
</div>
</Flex>
<SelectReveal
canCreateDelayedRevealBatch={props.canCreateDelayedRevealBatch}
client={props.client}
form={form}
/>
{form.watch("revealType") && (
<>
<CheckboxWithLabel>
<Checkbox
checked={form.watch("shuffle")}
className="mt-3"
onCheckedChange={(val) => form.setValue("shuffle", !!val)}
/>
<div className="flex flex-col items-center gap-1 md:flex-row">
<p>Shuffle the order of the NFTs before uploading.</p>
<em>This is an off-chain operation and is not provable.</em>
</div>
</CheckboxWithLabel>
<div className="w-full md:w-[61%]">
<TransactionButton
className="mt-4 w-full"
client={props.client}
disabled={!nftMetadatas.length}
isLoggedIn={props.isLoggedIn}
isPending={form.formState.isSubmitting}
transactionCount={1}
txChainID={props.chainId}
type="submit"
>
{form.formState.isSubmitting
? `Uploading ${nftMetadatas.length} NFTs`
: `Upload ${nftMetadatas.length} NFTs`}
</TransactionButton>
{props.children}
</div>
<Text mt={2} size="body.sm">
<UnderlineLink
className="text-primary-500"
href="https://support.thirdweb.com/dashboard/n5evQ4EfEjEifczEQaZ1hL/batch-upload-troubleshooting/5WMQFqfaUTU1C8NM8FtJ2X"
rel="noopener noreferrer"
target="_blank"
>
Experiencing issues uploading your files?
</UnderlineLink>
</Text>
</>
)}
</>
)}
</form>
);
};
interface SelectRevealProps {
form: ReturnType<typeof useBatchLazyMintForm>;
canCreateDelayedRevealBatch: boolean;
client: ThirdwebClient;
}
const SelectReveal: React.FC<SelectRevealProps> = ({
form,
client,
canCreateDelayedRevealBatch,
}) => {
const [show, setShow] = useState(false);
const imageUrl = form.watch("placeHolder.image");
return (
<Flex flexDir="column">
<Flex
flexDir={{ base: "column", md: "row" }}
gap={{ base: 3, md: 6 }}
mb={6}
>
<SelectOption
description="Collectors will immediately see the final NFT when they complete the minting"
isActive={form.watch("revealType") === "instant"}
name="Reveal upon mint"
onClick={() => form.setValue("revealType", "instant")}
/>
<SelectOption
description="Collectors will mint your placeholder image, then you reveal at a later time"
disabled={!canCreateDelayedRevealBatch}
disabledText="This contract doesn't implement Delayed Reveal"
isActive={form.watch("revealType") === "delayed"}
name="Delayed Reveal"
onClick={() => form.setValue("revealType", "delayed")}
/>
</Flex>
<div className="flex flex-col gap-3">
{form.watch("revealType") === "delayed" && (
<>
<Heading size="title.sm">Let&apos;s set a password</Heading>
<Alert borderRadius="lg" status="warning">
<AlertIcon />
You&apos;ll need this password to reveal your NFTs. Please save it
somewhere safe.
</Alert>
<Flex
flexDir={{ base: "column", md: "row" }}
gap={{ base: 4, md: 0 }}
>
<FormControl
isInvalid={
!!form.getFieldState("password", form.formState).error
}
isRequired
mr={4}
>
<FormLabel>Password</FormLabel>
<InputGroup>
<Input
{...form.register("password")}
placeholder="Choose password"
type={show ? "text" : "password"}
/>
<InputRightElement cursor="pointer">
{show ? (
<EyeIcon
className="size-3"
onClick={() => setShow(!show)}
/>
) : (
<EyeOffIcon
className="size-3"
onClick={() => setShow(!show)}
/>
)}
</InputRightElement>
</InputGroup>
<FormErrorMessage>
{
form.getFieldState("password", form.formState).error
?.message
}
</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={
!!form.getFieldState("confirmPassword", form.formState).error
}
isRequired
>
<FormLabel>Confirm password</FormLabel>
<Input
{...form.register("confirmPassword")}
placeholder="Confirm password"
type="password"
/>
<FormErrorMessage>
{
form.getFieldState("confirmPassword", form.formState).error
?.message
}
</FormErrorMessage>
</FormControl>
</Flex>
<div className="flex flex-col gap-5">
<Heading size="title.sm">Placeholder</Heading>
<FormControl
isInvalid={
!!form.getFieldState("placeHolder.image", form.formState)
.error
}
>
<FormLabel>Image</FormLabel>
<div className="w-auto md:w-[350px]">
<FileInput
accept={{ "image/*": [] }}
className="rounded border border-border transition-all duration-200"
client={client}
setValue={(file) =>
form.setValue("placeHolder.image", file)
}
showUploadButton
value={imageUrl}
/>
</div>
<FormHelperText>
You can optionally upload an image as the placeholder.
</FormHelperText>
<FormErrorMessage>
{
form.getFieldState("placeHolder.image", form.formState)
.error?.message
}
</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={
!!form.getFieldState("placeHolder.name", form.formState).error
}
isRequired
>
<FormLabel>Name</FormLabel>
<Input
{...form.register("placeHolder.name")}
placeholder="eg. My NFT (Coming soon)"
/>
<FormErrorMessage>
{
form.getFieldState("placeHolder.name", form.formState).error
?.message
}
</FormErrorMessage>
</FormControl>
<FormControl
isInvalid={
!!form.getFieldState("placeHolder.name", form.formState).error
}
>
<FormLabel>Description</FormLabel>
<Textarea
{...form.register("placeHolder.description")}
placeholder="eg. Reveal on July 15th!"
/>
<FormErrorMessage>
{
form.getFieldState(
"placeHolder.description",
form.formState,
).error?.message
}
</FormErrorMessage>
</FormControl>
</div>
</>
)}
</div>
</Flex>
);
};
@@ -1,237 +0,0 @@
/** biome-ignore-all lint/nursery/noNestedComponentDefinitions: FIXME */
import { FilePreview } from "@app/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/file-preview";
import {
Flex,
IconButton,
Portal,
Select,
Table,
TableContainer,
Tbody,
Td,
Th,
Thead,
Tr,
} from "@chakra-ui/react";
import {
ChevronFirstIcon,
ChevronLastIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react";
import { useMemo } from "react";
import { type Column, usePagination, useTable } from "react-table";
import type { ThirdwebClient } from "thirdweb";
import type { NFTInput } from "thirdweb/utils";
import { CodeClient } from "@/components/ui/code/code.client";
import { ToolTipLabel } from "@/components/ui/tooltip";
interface BatchTableProps {
data: NFTInput[];
portalRef: React.RefObject<HTMLDivElement | null>;
nextTokenIdToMint?: bigint;
client: ThirdwebClient;
}
export const BatchTable: React.FC<BatchTableProps> = ({
data,
portalRef,
nextTokenIdToMint,
client,
}) => {
const columns = useMemo(() => {
let cols: Column<NFTInput>[] = [];
if (nextTokenIdToMint !== undefined) {
cols = cols.concat({
accessor: (_row, index) => String(nextTokenIdToMint + BigInt(index)),
Header: "Token ID",
});
}
cols = cols.concat([
{
accessor: (row) => row.image,
Cell: ({ cell: { value } }: { cell: { value?: string } }) => (
<FilePreview
className="size-24 shrink-0 rounded-lg object-contain"
client={client}
srcOrFile={value}
/>
),
Header: "Image",
},
{
accessor: (row) => row.animation_url,
Cell: ({ cell: { value } }: { cell: { value?: string } }) => (
<FilePreview
className="size-24 shrink-0 rounded-lg"
client={client}
srcOrFile={value}
/>
),
Header: "Animation Url",
},
{ accessor: (row) => row.name, Header: "Name" },
{
accessor: (row) => (
<ToolTipLabel label={row.description}>
<p className="line-clamp-6 whitespace-pre-wrap">
{row.description}
</p>
</ToolTipLabel>
),
Header: "Description",
},
{
accessor: (row) => row.attributes || row.properties,
// biome-ignore lint/suspicious/noExplicitAny: FIXME
Cell: ({ cell }: { cell: any }) =>
cell.value ? (
<CodeClient
code={JSON.stringify(cell.value || {}, null, 2)}
lang="json"
scrollableClassName="max-w-[300px]"
/>
) : null,
Header: "Attributes",
},
{ accessor: (row) => row.external_url, Header: "External URL" },
{ accessor: (row) => row.background_color, Header: "Background Color" },
]);
return cols;
}, [nextTokenIdToMint, client]);
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
// Instead of using 'rows', we'll use page,
page,
// which has only the rows for the active page
// The rest of these things are super handy, too ;)
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
initialState: {
pageIndex: 0,
pageSize: 50,
},
},
// will be fixed with @tanstack/react-table v8
// eslint-disable-next-line react-compiler/react-compiler
usePagination,
);
// Render the UI for your table
return (
<Flex flexGrow={1} overflow="auto">
<TableContainer className="w-full" maxW="100%">
<Table {...getTableProps()}>
<Thead>
{headerGroups.map((headerGroup, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
<Tr {...headerGroup.getHeaderGroupProps()} key={index}>
{headerGroup.headers.map((column, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
<Th {...column.getHeaderProps()} border="none" key={i}>
<p className="text-muted-foreground">
{column.render("Header")}
</p>
</Th>
))}
</Tr>
))}
</Thead>
<Tbody {...getTableBodyProps()}>
{page.map((row, rowIndex) => {
prepareRow(row);
return (
<Tr
{...row.getRowProps()}
_last={{ borderBottomWidth: 0 }}
borderBottomWidth={1}
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
key={rowIndex}
>
{row.cells.map((cell, cellIndex) => {
return (
<Td
{...cell.getCellProps()}
borderBottomWidth="inherit"
borderColor="borderColor"
// biome-ignore lint/suspicious/noArrayIndexKey: FIXME
key={cellIndex}
>
{cell.render("Cell")}
</Td>
);
})}
</Tr>
);
})}
</Tbody>
</Table>
</TableContainer>
<Portal containerRef={portalRef}>
<div className="flex w-full items-center justify-center">
<div className="flex flex-row items-center gap-2">
<IconButton
aria-label="first page"
icon={<ChevronFirstIcon className="size-4" />}
isDisabled={!canPreviousPage}
onClick={() => gotoPage(0)}
/>
<IconButton
aria-label="previous page"
icon={<ChevronLeftIcon className="size-4" />}
isDisabled={!canPreviousPage}
onClick={() => previousPage()}
/>
<p className="whitespace-nowrap">
Page <strong>{pageIndex + 1}</strong> of{" "}
<strong>{pageOptions.length}</strong>
</p>
<IconButton
aria-label="next page"
icon={<ChevronRightIcon className="size-4" />}
isDisabled={!canNextPage}
onClick={() => nextPage()}
/>
<IconButton
aria-label="last page"
icon={<ChevronLastIcon className="size-4" />}
isDisabled={!canNextPage}
onClick={() => gotoPage(pageCount - 1)}
/>
<Select
onChange={(e) => {
setPageSize(Number.parseInt(e.target.value as string, 10));
}}
value={pageSize}
>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="250">250</option>
<option value="500">500</option>
</Select>
</div>
</div>
</Portal>
</Flex>
);
};
@@ -1,137 +0,0 @@
import { UploadIcon } from "lucide-react";
import { InlineCode } from "@/components/ui/inline-code";
import { UnorderedList } from "@/components/ui/List/List";
import { cn } from "@/lib/utils";
interface UploadStepProps {
// biome-ignore lint/suspicious/noExplicitAny: FIXME
getRootProps: any;
// biome-ignore lint/suspicious/noExplicitAny: FIXME
getInputProps: any;
hasFailed: boolean;
isDragActive: boolean;
}
export const UploadStep: React.FC<UploadStepProps> = ({
getRootProps,
hasFailed,
isDragActive,
getInputProps,
}) => {
return (
<div className="flex flex-col items-center gap-8 md:flex-row">
<div className="relative aspect-square w-full md:w-1/2">
<div
className={cn(
"flex h-full cursor-pointer rounded-md border border-border hover:border-blue-500",
hasFailed ? "bg-red-200" : "bg-background",
)}
{...getRootProps()}
>
<input {...getInputProps()} />
<div className="m-auto flex flex-col p-6">
<UploadIcon
className={cn(
"mx-auto mb-2 size-8",
hasFailed ? "text-red-500" : "text-gray-600",
)}
/>
{isDragActive ? (
<p className="text-center text-muted-foreground">
Drop the files here
</p>
) : (
<p
className={cn(
"text-center leading-[1.2]",
hasFailed ? "text-red-500" : "text-muted-foreground",
)}
>
{hasFailed
? `No valid CSV or JSON file found. Please make sure your NFT metadata includes at least a "name" field and try again.`
: "Drag & Drop files or folders here, or click to select files"}
</p>
)}
</div>
</div>
</div>
<div className="flex w-full flex-col gap-2 md:w-1/2">
<p className="text-lg">Requirements</p>
<UnorderedList>
<li>
Files <em>must</em> contain one .csv or .json file with metadata. -{" "}
<a
className="text-link-foreground hover:text-foreground"
download
href="/assets/examples/example.csv"
>
Download example.csv
</a>
.{" "}
<a
className="text-link-foreground hover:text-foreground"
download
href="/assets/examples/example.json"
>
Download example.json
</a>
.
</li>
<li>
The csv <em>must</em> have a <InlineCode code="name" /> column,
which defines the name of the NFT.
</li>
<li>
Asset names <em>must</em> be sequential 0,1,2,3...n.[extension]. It
doesn&apos;t matter at what number you begin. (Example:{" "}
<InlineCode code="131.png" />, <InlineCode code="132.png" />
).
</li>
<li>
Make sure to drag and drop the CSV/JSON and the images{" "}
<strong>at the same time</strong>.
</li>
</UnorderedList>
<p className="mt-4 text-lg">Options</p>
<UnorderedList>
<li>
Images and other file types can be used in combination.
<br />
<small>
They both have to follow the asset naming convention above.
(Example: <InlineCode code="0.png" /> and{" "}
<InlineCode code="0.mp4" />,<InlineCode code="1.png" /> and{" "}
<InlineCode code="1.glb" />, etc.)
</small>
</li>
<li>
When uploading files, we will upload them and pin them to IPFS
automatically for you. If you already have the files uploaded, you
can add an <InlineCode code="image" /> and/or
<InlineCode code="animation_url" /> column and add the IPFS hashes
there.{" "}
<a
className="text-link-foreground hover:text-foreground"
download
href="/assets/examples/example-with-ipfs.csv"
>
Download example.csv
</a>
</li>
<li>
If you want to make your media files map to your NFTs, you can add
the name of your files to the <InlineCode code="image" /> and
<InlineCode code="animation_url" /> column.{" "}
<a
className="text-link-foreground hover:text-foreground"
download
href="/assets/examples/example-with-maps.csv"
>
Download example.csv
</a>
</li>
</UnorderedList>
</div>
</div>
);
};
@@ -1,7 +1,7 @@
"use client";
import { AlertTriangleIcon } from "lucide-react";
import Link from "next/link";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { Button, type ButtonProps } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import type { ProductSKU } from "@/types/billing";
@@ -2,9 +2,9 @@
import { CheckIcon, DollarSignIcon } from "lucide-react";
import Link from "next/link";
import type React from "react";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { CheckoutButton } from "@/components/billing/billing";
import { RenewSubscriptionButton } from "@/components/billing/renew-subscription/renew-subscription-button";
import { RenewSubscriptionButton } from "@/components/billing/renew-subscription-button";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ToolTipLabel } from "@/components/ui/tooltip";
@@ -5,12 +5,12 @@ import { RefreshCwIcon } from "lucide-react";
import { useState, useTransition } from "react";
import { toast } from "sonner";
import { reSubscribePlan } from "@/actions/billing";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-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,3 +1,4 @@
import { ArrowLeftIcon } from "lucide-react";
import { useMemo, useState } from "react";
import { isAddress, NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from "thirdweb";
import { Button } from "@/components/ui/button";
@@ -109,10 +110,10 @@ export function CurrencySelector({
className="rounded-r-none rounded-l-md"
onClick={() => setIsAddingCurrency(false)}
>
&lt;-
<ArrowLeftIcon className="size-4" />
</Button>
<Input
className="w-full rounded-none"
className={cn("w-full rounded-none", className)}
onChange={(e) => setEditCustomCurrency(e.target.value)}
placeholder="ERC20 Address"
required
@@ -156,7 +157,7 @@ export function CurrencySelector({
: value?.toLowerCase()
}
>
<SelectTrigger>
<SelectTrigger className={className}>
<SelectValue placeholder="Select Currency" />
</SelectTrigger>
<SelectContent>
@@ -1,4 +1,3 @@
import { FilePreview } from "@app/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/file-preview";
import { FilePlusIcon, UploadIcon } from "lucide-react";
import { useCallback, useEffect, useRef } from "react";
import {
@@ -8,6 +7,7 @@ import {
useDropzone,
} from "react-dropzone";
import type { ThirdwebClient } from "thirdweb";
import { FilePreview } from "@/components/blocks/file-preview";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
@@ -2,6 +2,7 @@ import { AsteriskIcon, InfoIcon } from "lucide-react";
import type React from "react";
import { Label } from "@/components/ui/label";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { cn } from "../../lib/utils";
export function FormFieldSetup(props: {
htmlFor?: string;
@@ -10,13 +11,22 @@ export function FormFieldSetup(props: {
children: React.ReactNode;
tooltip?: React.ReactNode;
isRequired: boolean;
labelClassName?: string;
labelContainerClassName?: string;
helperText?: React.ReactNode;
className?: string;
}) {
return (
<div className={props.className}>
<div className="mb-2 inline-flex items-center gap-1">
<Label htmlFor={props.htmlFor}>{props.label}</Label>
<div
className={cn(
"mb-2 inline-flex items-center gap-1",
props.labelContainerClassName,
)}
>
<Label htmlFor={props.htmlFor} className={props.labelClassName}>
{props.label}
</Label>
{props.isRequired && (
<AsteriskIcon className="size-3.5 text-destructive-text" />
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
import { useState } from "react";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { Label } from "@/components/ui/label";
import {
Select,
@@ -1,6 +1,6 @@
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { ToolTipLabel } from "@/components/ui/tooltip";
@@ -29,16 +29,18 @@ export function MultiNetworkSelector(props: {
client: ThirdwebClient;
chainIds?: number[];
}) {
let { allChains, idToChain } = useAllChainsData();
if (props.chainIds && props.chainIds.length > 0) {
allChains = allChains.filter((chain) =>
props.chainIds?.includes(chain.chainId),
);
}
const { allChains, idToChain } = useAllChainsData();
const options = useMemo(() => {
let sortedChains = allChains;
let chains = allChains.filter((chain) => chain.status !== "deprecated");
if (props.chainIds && props.chainIds.length > 0) {
chains = allChains.filter((chain) =>
props.chainIds?.includes(chain.chainId),
);
}
let sortedChains = chains;
if (props.priorityChains) {
const priorityChainsSet = new Set();
@@ -69,7 +71,13 @@ export function MultiNetworkSelector(props: {
value: String(chain.chainId),
};
});
}, [allChains, props.priorityChains, idToChain, props.hideTestnets]);
}, [
allChains,
props.priorityChains,
idToChain,
props.hideTestnets,
props.chainIds,
]);
const searchFn = useCallback(
(option: Option, searchValue: string) => {
@@ -155,16 +163,38 @@ export function SingleNetworkSelector(props: {
disableDeprecated?: boolean;
placeholder?: string;
client: ThirdwebClient;
priorityChains?: number[];
}) {
const { allChains, idToChain } = useAllChainsData();
const chainsToShow = useMemo(() => {
let chains = allChains;
chains = chains.filter((chain) => chain.status !== "deprecated");
if (props.disableTestnets) {
chains = chains.filter((chain) => !chain.testnet);
}
if (props.priorityChains) {
const priorityChainsSet = new Set();
for (const chainId of props.priorityChains || []) {
priorityChainsSet.add(chainId);
}
const priorityChains = (props.priorityChains || [])
.map((chainId) => {
return idToChain.get(chainId);
})
.filter((v) => !!v);
const otherChains = allChains.filter(
(chain) => !priorityChainsSet.has(chain.chainId),
);
chains = [...priorityChains, ...otherChains];
}
if (props.chainIds) {
const chainIdSet = new Set(props.chainIds);
chains = chains.filter((chain) => chainIdSet.has(chain.chainId));
@@ -180,6 +210,8 @@ export function SingleNetworkSelector(props: {
props.chainIds,
props.disableTestnets,
props.disableDeprecated,
props.priorityChains,
idToChain,
]);
const options = useMemo(() => {
@@ -10,13 +10,14 @@ interface SignatureOption {
interface SignatureSelectorProps {
options: SignatureOption[];
value: string;
onChange: (val: string) => void;
value: string | string[];
onChange: (val: string | string[]) => void;
setAbi?: (abi: string) => void;
placeholder?: string;
disabled?: boolean;
secondaryTextFormatter?: (sig: SignatureOption) => string;
className?: string;
multiSelect?: boolean;
}
export function SignatureSelector({
@@ -28,6 +29,7 @@ export function SignatureSelector({
disabled,
secondaryTextFormatter,
className,
multiSelect = false,
}: SignatureSelectorProps) {
const [searchValue, setSearchValue] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
@@ -42,38 +44,96 @@ export function SignatureSelector({
}));
}, [options, secondaryTextFormatter]);
// Check if the current value is a custom value (not in options)
const isCustomValue = value && !options.some((opt) => opt.value === value);
// Add the custom value as an option if needed
const allOptions = useMemo(() => {
if (isCustomValue && value) {
return [...formattedOptions, { label: value, value }];
// Handle both single and multi-select values
const currentValues = useMemo((): string[] => {
if (multiSelect) {
if (Array.isArray(value)) {
return value.filter(
(val): val is string =>
val !== undefined && val !== null && val !== "",
);
} else {
return value ? [value] : [];
}
} else {
if (Array.isArray(value)) {
return value.length > 0 && value[0] ? [value[0]] : [];
} else {
return value ? [value] : [];
}
}
return formattedOptions;
}, [formattedOptions, isCustomValue, value]);
}, [value, multiSelect]);
// Single-select MultiSelect wrapper
// Check if the current values include custom values (not in options)
const customValues = useMemo((): string[] => {
return currentValues.filter(
(val): val is string =>
val !== undefined &&
val !== null &&
val !== "" &&
!options.some((opt) => opt.value === val),
);
}, [currentValues, options]);
// Add the custom values as options if needed
const allOptions = useMemo(() => {
const customOptions = customValues.map((val) => ({
label: val,
value: val,
}));
return [...formattedOptions, ...customOptions];
}, [formattedOptions, customValues]);
// Multi-select or single-select MultiSelect wrapper
const handleSelectedValuesChange = useCallback(
(selected: string[]) => {
// Always use the last selected value for single-select behavior
const selectedValue =
selected.length > 0 ? (selected[selected.length - 1] ?? "") : "";
onChange(selectedValue);
const found = options.find((opt) => opt.value === selectedValue);
if (setAbi) {
setAbi(found?.abi || "");
if (multiSelect) {
// Multi-select behavior
onChange(selected);
// For multi-select, we'll use the ABI from the first selected option that has one
const firstOptionWithAbi = selected.find((selectedValue) => {
const found = options.find((opt) => opt.value === selectedValue);
return found?.abi;
});
if (setAbi && firstOptionWithAbi) {
const found = options.find((opt) => opt.value === firstOptionWithAbi);
setAbi(found?.abi || "");
}
} else {
// Single-select behavior (maintain backward compatibility)
const selectedValue =
selected.length > 0 ? (selected[selected.length - 1] ?? "") : "";
onChange(selectedValue);
const found = options.find((opt) => opt.value === selectedValue);
if (setAbi) {
setAbi(found?.abi || "");
}
}
setSearchValue("");
},
[onChange, setAbi, options],
[onChange, setAbi, options, multiSelect],
);
// Handle custom value entry
const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Enter" && searchValue.trim()) {
if (!options.some((opt) => opt.value === searchValue.trim())) {
onChange(searchValue.trim());
if (multiSelect) {
// Add to existing values for multi-select
const currentArray = Array.isArray(value)
? value
: value
? [value]
: [];
const filteredArray = currentArray.filter(
(val): val is string => val !== undefined && val !== null,
);
const newValues = [...filteredArray, searchValue.trim()];
onChange(newValues);
} else {
// Replace value for single-select
onChange(searchValue.trim());
}
if (setAbi) setAbi("");
setSearchValue("");
// Optionally blur input
@@ -106,7 +166,7 @@ export function SignatureSelector({
customSearchInput={customSearchInput}
customTrigger={null}
disabled={disabled}
maxCount={1}
maxCount={multiSelect ? 100 : 1}
onSelectedValuesChange={handleSelectedValuesChange}
options={allOptions}
overrideSearchFn={(option, searchTerm) =>
@@ -116,11 +176,13 @@ export function SignatureSelector({
placeholder={placeholder}
renderOption={(option) => <span>{option.label}</span>}
searchPlaceholder={placeholder}
selectedValues={value ? [value] : []}
selectedValues={currentValues}
/>
{isCustomValue && (
{customValues.length > 0 && (
<div className="mt-2 rounded border border-warning-200 bg-warning-50 px-2 py-1 text-warning-700 text-xs">
You entered a custom signature. Please provide the ABI below.
{multiSelect
? `You entered ${customValues.length} custom signature${customValues.length > 1 ? "s" : ""}. Please provide the ABI below.`
: "You entered a custom signature. Please provide the ABI below."}
</div>
)}
</div>
@@ -1,6 +1,6 @@
"use client";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { Badge, type BadgeProps } from "@/components/ui/badge";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { cn } from "@/lib/utils";
@@ -9,11 +9,12 @@ 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 { fallbackChainIcon } from "@/constants/chain";
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";
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
import { Spinner } from "../ui/Spinner/Spinner";
type Option = { label: string; value: string };
@@ -121,7 +122,10 @@ export function TokenSelector(props: {
return option.label;
}
const resolvedSrc = token.iconUri
? replaceIpfsUrl(token.iconUri, props.client)
? resolveSchemeWithErrorHandler({
client: props.client,
uri: token.iconUri,
})
: fallbackChainIcon;
return (
@@ -186,16 +190,21 @@ export function TokenSelector(props: {
options={options}
overrideSearchFn={searchFn}
placeholder={
tokensQuery.isPending
? "Loading Tokens"
: props.placeholder || "Select Token"
tokensQuery.isPending ? (
<div className="flex items-center gap-2">
<Spinner className="size-4" />
<span>Loading tokens</span>
</div>
) : (
props.placeholder || "Select Token"
)
}
popoverContentClassName={props.popoverContentClassName}
renderOption={renderOption}
searchPlaceholder="Search by name or symbol"
showCheck={props.showCheck}
side={props.side}
value={selectedValue}
value={tokensQuery.isPending ? undefined : selectedValue}
/>
);
}
@@ -29,6 +29,7 @@ type ThirdwebAreaChartProps<TConfig extends ChartConfig> = {
title: string;
description?: string;
titleClassName?: string;
headerClassName?: string;
};
customHeader?: React.ReactNode;
// chart config
@@ -52,6 +53,12 @@ type ThirdwebAreaChartProps<TConfig extends ChartConfig> = {
toolTipLabelFormatter?: (label: string, payload: unknown) => React.ReactNode;
toolTipValueFormatter?: (value: unknown) => React.ReactNode;
emptyChartState?: React.ReactElement;
margin?: {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
};
export function ThirdwebAreaChart<TConfig extends ChartConfig>(
@@ -62,7 +69,7 @@ export function ThirdwebAreaChart<TConfig extends ChartConfig>(
return (
<Card className={props.className}>
{props.header && (
<CardHeader>
<CardHeader className={props.header.headerClassName}>
<CardTitle className={cn("mb-2", props.header.titleClassName)}>
{props.header.title}
</CardTitle>
@@ -85,7 +92,16 @@ export function ThirdwebAreaChart<TConfig extends ChartConfig>(
{props.emptyChartState}
</EmptyChartState>
) : (
<AreaChart accessibilityLayer data={props.data}>
<AreaChart
accessibilityLayer
data={props.data}
margin={{
right: props.margin?.right ?? 0,
left: props.margin?.left ?? 0,
bottom: props.margin?.bottom ?? 10,
top: props.margin?.top ?? 0,
}}
>
<CartesianGrid vertical={false} />
{props.yAxis && <YAxis axisLine={false} tickLine={false} />}
<XAxis
@@ -3,6 +3,7 @@ import type React from "react";
import { type Dispatch, type SetStateAction, useMemo } from "react";
import { CodeClient } from "@/components/ui/code/code.client";
import { TabButtons } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
export type CodeEnvironment =
| "javascript"
@@ -50,6 +51,7 @@ interface CodeSegmentProps {
isInstallCommand?: boolean;
hideTabs?: boolean;
onlyTabs?: boolean;
codeContainerClassName?: string;
}
export const CodeSegment: React.FC<CodeSegmentProps> = ({
@@ -59,6 +61,7 @@ export const CodeSegment: React.FC<CodeSegmentProps> = ({
isInstallCommand,
hideTabs,
onlyTabs,
codeContainerClassName,
}) => {
const activeEnvironment: CodeEnvironment = useMemo(() => {
return (
@@ -86,13 +89,12 @@ export const CodeSegment: React.FC<CodeSegmentProps> = ({
return (
<div
className={
"flex flex-col overflow-hidden rounded-lg border border-border"
"flex flex-col overflow-hidden rounded-lg border border-border grow"
}
>
{!hideTabs && (
<TabButtons
hideBottomLine={!!onlyTabs}
tabClassName="text-sm gap-2 !text-sm"
tabContainerClassName="px-3 pt-1.5 gap-0.5"
tabIconClassName="size-4"
tabs={environments.map((env) => ({
@@ -106,7 +108,11 @@ export const CodeSegment: React.FC<CodeSegmentProps> = ({
{onlyTabs ? null : (
<CodeClient
className="rounded-none border-none"
className={cn(
"rounded-none border-none grow",
codeContainerClassName,
)}
scrollableContainerClassName="h-full"
code={code}
lang={
isInstallCommand
@@ -0,0 +1,45 @@
"use client";
import { ArrowDownToLineIcon, FileTextIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { CodeClient } from "@/components/ui/code/code.client";
import { handleDownload } from "../download-file-button";
export function DownloadableCode(props: {
code: string;
lang: "csv" | "json";
fileNameWithExtension: string;
}) {
return (
<div className="!my-5 bg-card">
<p className="text-sm text-muted-foreground border border-b-0 px-4 py-3 pr-3.5 rounded-lg rounded-b-none flex items-center justify-between">
<span className="flex items-center gap-1.5">
<FileTextIcon className="size-3.5" />
{props.fileNameWithExtension}
</span>
<Button
className="h-auto bg-background p-2"
onClick={() => {
handleDownload({
fileContent: props.code,
fileFormat:
props.lang === "csv" ? "text/csv" : "application/json",
fileNameWithExtension: props.fileNameWithExtension,
});
}}
size="sm"
variant="outline"
>
<ArrowDownToLineIcon className="size-3" />
</Button>
</p>
<div className="relative">
<CodeClient
code={props.code}
lang={props.lang}
scrollableClassName="max-h-[300px] bg-background bg-card"
className="rounded-t-none"
/>
</div>
</div>
);
}
@@ -1,12 +1,39 @@
"use client";
import { XIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { useLocalStorage } from "@/hooks/useLocalStorage";
export function DismissibleAlert(props: {
export function DismissibleAlert(
props: {
title: React.ReactNode;
header?: React.ReactNode;
className?: string;
description: React.ReactNode;
children?: React.ReactNode;
} & (
| {
preserveState: true;
localStorageId: string;
}
| {
preserveState: false;
}
),
) {
if (props.preserveState) {
return <DismissibleAlertWithLocalStorage {...props} />;
}
return <DismissibleAlertWithoutLocalStorage {...props} />;
}
function DismissibleAlertWithLocalStorage(props: {
title: React.ReactNode;
header?: React.ReactNode;
description: React.ReactNode;
children?: React.ReactNode;
localStorageId: string;
}) {
const [isVisible, setIsVisible] = useLocalStorage(
@@ -17,19 +44,48 @@ export function DismissibleAlert(props: {
if (!isVisible) return null;
return <AlertUI {...props} onClose={() => setIsVisible(false)} />;
}
function DismissibleAlertWithoutLocalStorage(props: {
title: React.ReactNode;
description: React.ReactNode;
children?: React.ReactNode;
}) {
const [isVisible, setIsVisible] = useState(true);
if (!isVisible) return null;
return <AlertUI {...props} onClose={() => setIsVisible(false)} />;
}
function AlertUI(props: {
title: React.ReactNode;
header?: React.ReactNode;
description: React.ReactNode;
children?: React.ReactNode;
className?: string;
onClose: () => void;
}) {
return (
<div className="relative rounded-lg border border-border bg-card p-4">
<Button
aria-label="Close alert"
className="absolute top-4 right-4 h-auto w-auto p-1 text-muted-foreground"
onClick={() => setIsVisible(false)}
variant="ghost"
>
<XIcon className="size-5" />
</Button>
<div>
<h2 className="mb-0.5 font-semibold">{props.title} </h2>
<div className="text-muted-foreground text-sm">{props.description}</div>
<div className={props.className}>
<div className="relative rounded-lg border border-border bg-card p-4 lg:p-6 overflow-hidden">
<Button
aria-label="Close alert"
className="absolute top-4 right-4 h-auto w-auto p-1 text-muted-foreground"
onClick={props.onClose}
variant="ghost"
>
<XIcon className="size-5" />
</Button>
<div>
{props.header}
<h2 className="mb-0.5 font-semibold">{props.title} </h2>
<div className="text-muted-foreground text-sm">
{props.description}
</div>
{props.children}
</div>
</div>
</div>
);
@@ -3,12 +3,15 @@ import { cn } from "@/lib/utils";
export type Segment = {
label: string;
percent: number;
value: string;
color: string;
};
type DistributionBarChartProps = {
segments: Segment[];
title: string;
title?: string;
titleClassName?: string;
barClassName?: string;
};
export function DistributionBarChart(props: DistributionBarChartProps) {
@@ -21,24 +24,36 @@ export function DistributionBarChart(props: DistributionBarChartProps) {
return (
<div>
<div className="mb-2 flex items-center justify-between">
<h3 className="font-medium text-sm">{props.title}</h3>
<div
className={cn(
"font-medium text-muted-foreground text-sm",
invalidTotalPercentage && "text-red-500",
)}
>
Total: {totalPercentage}%
{props.title && (
<div className="mb-2 flex items-center justify-between">
<h3 className={cn("font-medium text-sm", props.titleClassName)}>
{props.title}
</h3>
<div
className={cn(
"font-medium text-muted-foreground text-sm",
invalidTotalPercentage && "text-red-500",
)}
>
Total: {totalPercentage}%
</div>
</div>
</div>
)}
{/* Bar */}
<div className="flex h-3 overflow-hidden rounded-lg">
<div
className={cn(
"flex h-3 overflow-hidden rounded-lg",
props.barClassName,
)}
>
{props.segments.map((segment) => {
return (
<div
className="flex h-full items-center justify-center transition-all duration-200"
className={cn(
"flex h-full items-center justify-center transition-all duration-200",
segment.percent > 0 && "border-r-2 border-background",
)}
key={segment.label}
style={{
backgroundColor: segment.color,
@@ -67,7 +82,7 @@ export function DistributionBarChart(props: DistributionBarChartProps) {
"text-destructive-text",
)}
>
{segment.label}: {segment.percent}%
{segment.label}: {segment.value}
</p>
</div>
);
@@ -1,5 +1,6 @@
import { ArrowDownToLineIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export function handleDownload(params: {
fileContent: string;
@@ -22,10 +23,14 @@ export function DownloadFileButton(props: {
fileNameWithExtension: string;
fileFormat: "text/csv" | "application/json";
label: string;
variant?: "default" | "outline";
className?: string;
iconClassName?: string;
}) {
return (
<Button
className="gap-2"
className={cn("gap-2", props.className)}
variant={props.variant}
onClick={() => {
handleDownload({
fileContent: props.fileContent,
@@ -35,7 +40,7 @@ export function DownloadFileButton(props: {
}}
size="sm"
>
<ArrowDownToLineIcon className="size-4" />
<ArrowDownToLineIcon className={cn("size-4", props.iconClassName)} />
{props.label}
</Button>
);
@@ -26,7 +26,7 @@ export function DropZone(props: {
return (
<div
className={cn(
"flex cursor-pointer items-center justify-center rounded-md border border-dashed bg-card py-10 hover:border-active-border",
"flex cursor-pointer items-center justify-center rounded-md border border-dashed bg-card py-10 hover:border-active-border px-4",
props.isError &&
"border-red-500 bg-red-200/30 text-red-500 hover:border-red-600 dark:border-red-900 dark:bg-red-900/30 dark:hover:border-red-800",
props.className,
@@ -37,7 +37,12 @@ export function FilePreview(props: {
if (!objectUrl) {
return (
<div className={cn("flex items-center justify-center", props.className)}>
<div
className={cn(
"flex items-center justify-center bg-accent",
props.className,
)}
>
<ImageOffIcon className="size-6 text-muted-foreground" />
</div>
);
@@ -56,7 +61,10 @@ export function FilePreview(props: {
return (
<MediaRenderer
className={cn(props.className, "[&>div]:!bg-muted")}
className={cn(
props.className,
"[&>div]:!bg-accent [&_a]:!text-muted-foreground [&_a]:!no-underline [&_svg]:!size-6 [&_svg]:!text-muted-foreground relative overflow-hidden",
)}
client={props.client}
src={objectUrl}
/>
@@ -0,0 +1,49 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
import { useState } from "react";
import { ConnectButton, ThirdwebProvider } from "thirdweb/react";
import { Button } from "@/components/ui/button";
import { storybookThirdwebClient } from "@/storybook/utils";
import { FundWalletModal } from "./index";
const meta: Meta<typeof FundWalletModal> = {
title: "Blocks/FundWalletModal",
component: Variant,
decorators: [
(Story) => (
<ThirdwebProvider>
<div className="p-10">
<ConnectButton client={storybookThirdwebClient} />
<div className="h-4" />
<Story />
</div>
</ThirdwebProvider>
),
],
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Test: Story = {
args: {},
};
function Variant() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<Button type="button" onClick={() => setIsOpen(true)}>
Open
</Button>
<FundWalletModal
open={isOpen}
onOpenChange={setIsOpen}
title="This is a title"
description="This is a description"
recipientAddress="0x83Dd93fA5D8343094f850f90B3fb90088C1bB425"
client={storybookThirdwebClient}
/>
</div>
);
}
@@ -0,0 +1,292 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
import { useTheme } from "next-themes";
import { useState } from "react";
import { useForm } from "react-hook-form";
import type { ThirdwebClient } from "thirdweb";
import { defineChain } from "thirdweb/chains";
import { CheckoutWidget, useActiveWalletChain } from "thirdweb/react";
import { z } from "zod";
import {
reportFundWalletFailed,
reportFundWalletSuccessful,
} from "@/analytics/report";
import { SingleNetworkSelector } from "@/components/blocks/NetworkSelectors";
import { TokenSelector } from "@/components/blocks/TokenSelector";
import { Button } from "@/components/ui/button";
import { DecimalInput } from "@/components/ui/decimal-input";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { getSDKTheme } from "@/utils/sdk-component-theme";
import { WalletAddress } from "../wallet-address";
const formSchema = z.object({
chainId: z.number({
required_error: "Chain is required",
}),
token: z.object(
{
chainId: z.number(),
address: z.string(),
symbol: z.string(),
name: z.string(),
decimals: z.number(),
},
{
required_error: "Token is required",
},
),
amount: z
.string()
.min(1, "Amount is required")
.refine((value) => {
const num = Number(value);
return !Number.isNaN(num) && num > 0;
}, "Amount must be greater than 0"),
});
type FormData = z.infer<typeof formSchema>;
type FundWalletModalProps = {
open: boolean;
onOpenChange: (open: boolean) => void;
title: string;
description: string;
recipientAddress: string;
client: ThirdwebClient;
defaultChainId?: number;
checkoutWidgetTitle?: string;
};
export function FundWalletModal(props: FundWalletModalProps) {
return (
<Dialog open={props.open} onOpenChange={props.onOpenChange}>
<DialogContent className="p-0 gap-0 !w-full !max-w-md">
<FundWalletModalContent
open={props.open}
onOpenChange={props.onOpenChange}
title={props.title}
description={props.description}
recipientAddress={props.recipientAddress}
client={props.client}
defaultChainId={props.defaultChainId}
checkoutWidgetTitle={props.checkoutWidgetTitle}
/>
</DialogContent>
</Dialog>
);
}
function FundWalletModalContent(props: FundWalletModalProps) {
const [step, setStep] = useState<"form" | "checkout">("form");
const activeChain = useActiveWalletChain();
const { theme } = useTheme();
const form = useForm<FormData>({
defaultValues: {
chainId: props.defaultChainId || activeChain?.id || 1,
token: undefined,
amount: "0.1",
},
mode: "onChange",
resolver: zodResolver(formSchema),
});
const selectedChainId = form.watch("chainId");
return (
<div>
{step === "form" ? (
<Form {...form}>
<form
onSubmit={form.handleSubmit(() => {
setStep("checkout");
})}
>
<DialogHeader className="p-4 lg:p-6">
<DialogTitle>{props.title}</DialogTitle>
<DialogDescription>{props.description}</DialogDescription>
</DialogHeader>
<div className="space-y-4 px-4 lg:px-6 pb-8">
<div>
<h3 className="text-sm font-medium"> Recipient</h3>
<WalletAddress
address={props.recipientAddress}
client={props.client}
className="py-1 h-auto"
iconClassName="size-4"
/>
</div>
<FormField
control={form.control}
name="chainId"
render={({ field }) => (
<FormItem>
<FormLabel>Chain</FormLabel>
<FormControl>
<SingleNetworkSelector
className="bg-card"
chainId={field.value}
onChange={(token) => {
field.onChange(token);
form.resetField("token", {
defaultValue: undefined,
});
}}
client={props.client}
placeholder="Select a chain"
disableDeprecated
disableTestnets
disableChainId
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="token"
render={({ field }) => {
return (
<FormItem>
<FormLabel>Token</FormLabel>
<FormControl>
<TokenSelector
className="bg-card"
disableAddress
selectedToken={
field.value
? {
chainId: field.value.chainId,
address: field.value.address,
}
: undefined
}
onChange={field.onChange}
chainId={selectedChainId}
client={props.client}
placeholder="Select a token"
enabled={!!selectedChainId}
addNativeTokenIfMissing={true}
showCheck={true}
/>
</FormControl>
<FormMessage />
</FormItem>
);
}}
/>
<FormField
control={form.control}
name="amount"
render={({ field }) => (
<FormItem>
<FormLabel>Amount</FormLabel>
<FormControl>
<div className="relative">
<DecimalInput
className="bg-card !text-xl h-auto font-semibold"
value={field.value}
onChange={field.onChange}
placeholder="0.1"
/>
{form.watch("token") && (
<div className="absolute right-4 top-1/2 -translate-y-1/2 text-sm text-muted-foreground">
{form.watch("token").symbol}
</div>
)}
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className="flex justify-end gap-3 p-4 lg:p-6 bg-card border-t rounded-b-lg">
<Button
variant="outline"
onClick={() => props.onOpenChange(false)}
>
Cancel
</Button>
<Button type="submit" className="gap-2">
Next
<ArrowRightIcon className="w-4 h-4" />
</Button>
</div>
</form>
</Form>
) : (
<div>
<DialogHeader className="sr-only">
<DialogTitle>{props.title}</DialogTitle>
<DialogDescription>{props.description}</DialogDescription>
</DialogHeader>
<div>
<CheckoutWidget
client={props.client}
// eslint-disable-next-line no-restricted-syntax
chain={defineChain(form.getValues("chainId"))}
tokenAddress={form.getValues("token").address as `0x${string}`}
amount={form.getValues("amount")}
seller={props.recipientAddress as `0x${string}`}
showThirdwebBranding={false}
className="!w-full !max-w-full !min-w-0 !rounded-b-none !border-none"
theme={getSDKTheme(theme === "dark" ? "dark" : "light")}
name={props.checkoutWidgetTitle}
onSuccess={() => {
reportFundWalletSuccessful();
}}
onError={(error) => {
reportFundWalletFailed({
errorMessage: error.message,
});
}}
/>
</div>
<div className="flex justify-end gap-3 p-4 lg:p-6 bg-card border-t rounded-b-lg">
<Button
variant="outline"
onClick={() => setStep("form")}
className="gap-2"
>
<ArrowLeftIcon className="size-4 text-muted-foreground" />
Back
</Button>
<Button
className="gap-2"
variant="outline"
onClick={() => props.onOpenChange(false)}
>
Cancel
</Button>
</div>
</div>
)}
</div>
);
}
@@ -94,7 +94,7 @@ export const MarkdownRenderer: React.FC<{
<h2
className={cn(
commonHeadingClassName,
"mb-3 border-border border-b pb-2 text-xl md:text-2xl",
"mb-3 border-dashed border-b pb-2 text-xl md:text-2xl",
)}
{...cleanedProps(props)}
/>
@@ -105,7 +105,7 @@ export const MarkdownRenderer: React.FC<{
{...cleanedProps(props)}
className={cn(
commonHeadingClassName,
"mt-8 mb-3 border-border border-b pb-2 text-lg md:text-xl",
"mt-8 mb-3 border-dashed border-b pb-2 text-lg md:text-xl",
)}
/>
),
@@ -147,7 +147,7 @@ export const MarkdownRenderer: React.FC<{
li: ({ children: c, ...props }) => (
<li
className={cn(
"mb-1.5 text-muted-foreground leading-loose [&>p]:m-0",
"text-muted-foreground leading-relaxed [&>p]:m-0",
markdownProps.li?.className,
)}
{...cleanedProps(props)}
@@ -157,7 +157,7 @@ export const MarkdownRenderer: React.FC<{
),
ol: (props) => (
<ol
className="mb-4 list-outside list-decimal pl-5 [&_ol_li:first-of-type]:mt-1.5 [&_ul_li:first-of-type]:mt-1.5"
className="mb-4 list-outside list-decimal pl-4 space-y-2 [&>li]:first:mt-2"
{...cleanedProps(props)}
/>
),
@@ -165,7 +165,7 @@ export const MarkdownRenderer: React.FC<{
p: (props) => (
<p
className={cn(
"mb-4 text-muted-foreground leading-loose",
"mb-3 text-muted-foreground leading-7",
markdownProps.p?.className,
)}
{...cleanedProps(props)}
@@ -201,7 +201,7 @@ export const MarkdownRenderer: React.FC<{
ul: (props) => {
return (
<ul
className="mb-4 list-outside list-disc pl-5 [&_ol_li:first-of-type]:mt-1.5 [&_ul_li:first-of-type]:mt-1.5"
className="mb-4 list-outside list-disc pl-4 space-y-2 [&>li]:first:mt-2"
{...cleanedProps(props)}
/>
);
@@ -64,6 +64,7 @@ export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
popoverContentClassName,
showSelectedValuesInModal = false,
customSearchInput,
customTrigger,
...props
},
ref,
@@ -144,13 +145,18 @@ export const MultiSelect = forwardRef<HTMLButtonElement, MultiSelectProps>(
// scroll to top when options change
const popoverElRef = useRef<HTMLDivElement>(null);
// Filter out customTrigger from props to avoid passing it to Button
const buttonProps = Object.fromEntries(
Object.entries(props).filter(([key]) => key !== "customTrigger"),
) as React.ButtonHTMLAttributes<HTMLButtonElement>;
return (
<Popover modal onOpenChange={setIsPopoverOpen} open={isPopoverOpen}>
<PopoverTrigger asChild>
{props.customTrigger || (
{customTrigger || (
<Button
ref={ref}
{...props}
{...buttonProps}
className={cn(
"flex h-auto min-h-10 w-full items-center justify-between rounded-md border border-border bg-inherit p-3 hover:bg-inherit",
className,
@@ -34,7 +34,7 @@ export function MultiStepStatus<T extends string>(props: {
}) {
return (
<DynamicHeight>
<div className="space-y-4">
<div className="space-y-4 overflow-hidden">
{props.steps.map((step) => (
<div className="flex items-start space-x-3 " key={step.label}>
{step.status.type === "completed" ? (
@@ -46,7 +46,7 @@ export function MultiStepStatus<T extends string>(props: {
) : (
<CircleIcon className="mt-0.5 size-5 flex-shrink-0 text-muted-foreground/70" />
)}
<div className="flex-1">
<div className="grow">
<p
className={`font-medium ${
step.status.type === "pending"
@@ -73,7 +73,7 @@ export function MultiStepStatus<T extends string>(props: {
{step.status.type === "error"
? props.renderError?.(step, step.status.message) || (
<div className="mt-1 space-y-2">
<p className="mb-1 text-red-500 text-sm">
<p className="mb-1 text-red-500 text-sm whitespace-pre-wrap break-all">
{step.status.message}
</p>
<Button
@@ -22,7 +22,7 @@ interface SelectWithSearchProps
}[];
value: string | undefined;
onValueChange: (value: string) => void;
placeholder: string;
placeholder: string | React.ReactNode;
searchPlaceholder?: string;
className?: string;
overrideSearchFn?: (
@@ -1,9 +1,9 @@
"use client";
import { CrownIcon, LockIcon, SparklesIcon } from "lucide-react";
import { CrownIcon, LockIcon } from "lucide-react";
import Link from "next/link";
import type React from "react";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { TeamPlanBadge } from "@/components/blocks/TeamPlanBadge";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -111,18 +111,15 @@ export function UpsellContent(props: {
<CardContent className="space-y-6">
{props.benefits && props.benefits.length > 0 && (
<div className="space-y-3">
<h4 className="font-semibold text-muted-foreground text-sm uppercase tracking-wide">
What you'll get:
<h4 className="font-semibold text-foreground text-sm capitalize text-center">
What you'll get
</h4>
<div className="grid gap-2">
<div className="grid gap-1.5">
{props.benefits.map((benefit) => (
<div
className="flex items-center gap-3"
className="flex items-center justify-center gap-3 text-center text-balance"
key={benefit.description}
>
<div className="flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-accent">
<SparklesIcon className="h-3 w-3 text-success-text" />
</div>
<span className="text-sm">{benefit.description}</span>
{benefit.status === "soon" && (
<Badge className="text-xs" variant="secondary">
@@ -1,5 +1,5 @@
"use client";
import { CheckIcon, CopyIcon, XIcon } from "lucide-react";
import { CheckIcon, CircleSlashIcon, CopyIcon, XIcon } from "lucide-react";
import { useMemo } from "react";
import { isAddress, type ThirdwebClient, ZERO_ADDRESS } from "thirdweb";
import { Blobbie, type SocialProfile, useSocialProfiles } from "thirdweb/react";
@@ -23,7 +23,7 @@ export function WalletAddress(props: {
className?: string;
iconClassName?: string;
client: ThirdwebClient;
preventOpenOnFocus?: boolean;
fallbackIcon?: React.ReactNode;
}) {
// default back to zero address if no address provided
const address = useMemo(() => props.address || ZERO_ADDRESS, [props.address]);
@@ -60,18 +60,22 @@ export function WalletAddress(props: {
// special case for zero address
if (address === ZERO_ADDRESS) {
return (
<span className={cn("cursor-pointer font-mono", props.className)}>
{shortenedAddress}
</span>
<div className="flex items-center gap-2 py-2">
<CircleSlashIcon
className={cn("size-6 text-muted-foreground/70", props.iconClassName)}
/>
<span
className={cn("cursor-pointer font-mono text-sm", props.className)}
>
{shortenedAddress}
</span>
</div>
);
}
return (
<HoverCard>
<HoverCardTrigger
asChild
tabIndex={props.preventOpenOnFocus ? -1 : undefined}
>
<HoverCardTrigger asChild tabIndex={-1}>
<Button
className={cn(
"flex flex-row items-center gap-2 px-0",
@@ -86,6 +90,7 @@ export function WalletAddress(props: {
iconClassName={props.iconClassName}
profiles={profiles.data || []}
thirdwebClient={props.client}
fallbackIcon={props.fallbackIcon}
/>
)}
<span className="cursor-pointer font-mono">
@@ -177,6 +182,7 @@ function WalletAvatar(props: {
profiles: SocialProfile[];
thirdwebClient: ThirdwebClient;
iconClassName?: string;
fallbackIcon?: React.ReactNode;
}) {
const avatar = useMemo(() => {
return props.profiles.find(
@@ -196,13 +202,15 @@ function WalletAvatar(props: {
return (
<div
className={cn("size-6 overflow-hidden rounded-full", props.iconClassName)}
className={cn("size-5 overflow-hidden rounded-full", props.iconClassName)}
>
{resolvedAvatarSrc ? (
<Img
className={cn("size-6 object-cover", props.iconClassName)}
className={cn("size-5 object-cover", props.iconClassName)}
src={resolvedAvatarSrc}
/>
) : props.fallbackIcon ? (
props.fallbackIcon
) : (
<Blobbie
address={props.address}
@@ -116,13 +116,12 @@ export function ChatBar(props: {
) : (
<Button
aria-label="Send"
className="!h-auto w-auto border border-nebula-pink-foreground p-2 disabled:opacity-100"
className="!h-auto w-auto p-2 disabled:opacity-100"
disabled={message.trim() === "" || props.isConnectingWallet}
onClick={() => {
if (message.trim() === "") return;
handleSubmit(message);
}}
variant="pink"
>
<ArrowUpIcon className="size-4" />
</Button>
@@ -1,8 +1,10 @@
"use client";
import { MessageCircleIcon, XIcon } from "lucide-react";
import { useSelectedLayoutSegments } from "next/navigation";
import { useCallback, useRef, useState } from "react";
import { createThirdwebClient } from "thirdweb";
import type { Team } from "@/api/team/get-team";
import { Button } from "@/components/ui/button";
import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "@/constants/public-envs";
import { cn } from "@/lib/utils";
@@ -14,22 +16,22 @@ const client = createThirdwebClient({
});
export function CustomChatButton(props: {
isLoggedIn: boolean;
networks: "mainnet" | "testnet" | "all" | null;
isFloating: boolean;
pageType: "chain" | "contract" | "support";
label: string;
examplePrompts: string[];
authToken: string | undefined;
teamId: string | undefined;
authToken: string;
team: Team;
clientId: string | undefined;
requireLogin?: boolean;
}) {
const layoutSegments = useSelectedLayoutSegments();
const [isOpen, setIsOpen] = useState(false);
const [hasBeenOpened, setHasBeenOpened] = useState(false);
const closeModal = useCallback(() => setIsOpen(false), []);
const ref = useRef<HTMLDivElement>(null);
if (layoutSegments[0] === "~" && layoutSegments[1] === "support") {
return null;
}
return (
<>
{/* Inline Button (not floating) */}
@@ -54,14 +56,14 @@ export function CustomChatButton(props: {
ref={ref}
>
{/* Header with close button */}
<div className="flex items-center justify-between border-b px-4 py-2">
<div className="flex items-center justify-between border-b px-4 py-4">
<div className="flex items-center gap-2 font-semibold text-lg">
<MessageCircleIcon className="size-5 text-muted-foreground" />
{props.label}
</div>
<Button
aria-label="Close chat"
className="h-auto w-auto p-1 text-muted-foreground"
className="h-auto w-auto p-1 text-muted-foreground rounded-full"
onClick={closeModal}
size="icon"
variant="ghost"
@@ -80,9 +82,7 @@ export function CustomChatButton(props: {
message: prompt,
title: prompt,
}))}
networks={props.networks}
requireLogin={props.requireLogin}
teamId={props.teamId}
team={props.team}
/>
)}
</div>
@@ -1,44 +1,36 @@
"use client";
import { ArrowRightIcon } from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useCallback, useState } from "react";
import type { ThirdwebClient } from "thirdweb";
import { useActiveWalletConnectionStatus } from "thirdweb/react";
import type { Team } from "@/api/team/get-team";
import { Button } from "@/components/ui/button";
import { NebulaIcon } from "@/icons/NebulaIcon";
import { ThirdwebMiniLogo } from "../../../app/(app)/components/ThirdwebMiniLogo";
import { ChatBar } from "./ChatBar";
import type { UserMessage, UserMessageContent } from "./CustomChats";
import { type CustomChatMessage, CustomChats } from "./CustomChats";
import type { ExamplePrompt, NebulaContext } from "./types";
import type { ExamplePrompt } from "./types";
export default function CustomChatContent(props: {
authToken: string | undefined;
teamId: string | undefined;
team: Team;
clientId: string | undefined;
client: ThirdwebClient;
examplePrompts: ExamplePrompt[];
networks: NebulaContext["networks"];
requireLogin?: boolean;
}) {
if (props.requireLogin !== false && !props.authToken) {
return <LoggedOutStateChatContent />;
}
return (
<CustomChatContentLoggedIn
authToken={props.authToken || ""}
client={props.client}
clientId={props.clientId}
examplePrompts={props.examplePrompts}
teamId={props.teamId}
team={props.team}
/>
);
}
function CustomChatContentLoggedIn(props: {
authToken: string;
teamId: string | undefined;
team: Team;
clientId: string | undefined;
client: ThirdwebClient;
examplePrompts: ExamplePrompt[];
@@ -55,6 +47,9 @@ function CustomChatContentLoggedIn(props: {
const [enableAutoScroll, setEnableAutoScroll] = useState(false);
const connectionStatus = useActiveWalletConnectionStatus();
const [showSupportForm, setShowSupportForm] = useState(false);
const [productLabel, setProductLabel] = useState("");
const handleSendMessage = useCallback(
async (userMessage: UserMessage) => {
const abortController = new AbortController();
@@ -96,7 +91,7 @@ function CustomChatContentLoggedIn(props: {
headers: {
Authorization: `Bearer ${props.authToken}`,
"Content-Type": "application/json",
...(props.teamId ? { "x-team-id": props.teamId } : {}),
"x-team-id": props.team.id,
...(props.clientId ? { "x-client-id": props.clientId } : {}),
},
method: "POST",
@@ -132,7 +127,7 @@ function CustomChatContentLoggedIn(props: {
setEnableAutoScroll(false);
}
},
[props.authToken, props.clientId, props.teamId, sessionId],
[props.authToken, props.clientId, props.team.id, sessionId],
);
const handleFeedback = useCallback(
@@ -165,7 +160,7 @@ function CustomChatContentLoggedIn(props: {
headers: {
Authorization: `Bearer ${props.authToken}`,
"Content-Type": "application/json",
...(props.teamId ? { "x-team-id": props.teamId } : {}),
"x-team-id": props.team.id,
},
method: "POST",
});
@@ -188,9 +183,20 @@ function CustomChatContentLoggedIn(props: {
// Consider implementing retry logic here
}
},
[sessionId, props.authToken, props.teamId, messages],
[sessionId, props.authToken, props.team.id, messages],
);
const handleAddSuccessMessage = useCallback((message: string) => {
setMessages((prev) => [
...prev,
{
type: "assistant" as const,
text: message,
request_id: undefined,
},
]);
}, []);
const showEmptyState = !userHasSubmittedMessage && messages.length === 0;
return (
<div className="flex grow flex-col overflow-hidden">
@@ -212,6 +218,12 @@ function CustomChatContentLoggedIn(props: {
sessionId={sessionId}
setEnableAutoScroll={setEnableAutoScroll}
useSmallText
showSupportForm={showSupportForm}
setShowSupportForm={setShowSupportForm}
productLabel={productLabel}
setProductLabel={setProductLabel}
team={props.team}
addSuccessMessage={handleAddSuccessMessage}
/>
)}
<ChatBar
@@ -245,42 +257,6 @@ function CustomChatContentLoggedIn(props: {
);
}
function LoggedOutStateChatContent() {
const pathname = usePathname();
return (
<div className="flex grow flex-col items-center justify-center p-4">
<div className="mb-4 flex justify-center">
<div className="rounded-full border p-1">
<div className="rounded-full border bg-card p-2">
<NebulaIcon className="size-7 text-muted-foreground" />
</div>
</div>
</div>
<h1 className="px-4 text-center font-semibold text-3xl tracking-tight md:text-4xl">
How can I help you <br className="max-sm:hidden" />
today?
</h1>
<div className="h-3" />
<p className="text-base text-muted-foreground">
Sign in to use AI Assistant
</p>
<div className="h-5" />
<Button asChild>
<Link
className="w-full max-w-96 gap-2"
href={`/login?next=${encodeURIComponent(pathname)}`}
>
Sign in
<ArrowRightIcon className="size-4" />
</Link>
</Button>
</div>
);
}
function EmptyStateChatPageContent(props: {
sendMessage: (message: UserMessage) => void;
examplePrompts: { title: string; message: string }[];
@@ -288,9 +264,12 @@ function EmptyStateChatPageContent(props: {
return (
<div className="flex flex-1 flex-col items-center justify-center overflow-auto p-4 ">
<div className="mb-4 flex justify-center">
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/20 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-1">
<div className="rounded-full border-[1.5px] border-nebula-pink-foreground/40 bg-[hsl(var(--nebula-pink-foreground)/5%)] p-2">
<NebulaIcon className="size-7 text-nebula-pink-foreground" />
<div className="rounded-full border p-1 bg-muted/20">
<div className="rounded-full border p-2 bg-inverted">
<ThirdwebMiniLogo
isMonoChrome
className="size-7 text-inverted-foreground"
/>
</div>
</div>
</div>
@@ -301,11 +280,12 @@ function EmptyStateChatPageContent(props: {
</h1>
<div className="h-6" />
<div className="flex max-w-lg flex-col flex-wrap justify-center gap-2.5">
<div className="flex flex-col items-center justify-center gap-2.5 overflow-hidden">
{props.examplePrompts.map((prompt) => (
<Button
disabled={false}
key={prompt.title}
className="rounded-full text-xs sm:text-sm truncate bg-card w-fit h-auto py-1.5 whitespace-pre-wrap"
onClick={() =>
props.sendMessage({
content: [
@@ -1,15 +1,26 @@
import {
AlertCircleIcon,
MessageCircleIcon,
ArrowRightIcon,
ThumbsDownIcon,
ThumbsUpIcon,
} from "lucide-react";
import { useEffect, useRef, useState } from "react";
import type { ThirdwebClient } from "thirdweb";
import type { Team } from "@/api/team/get-team";
import { MarkdownRenderer } from "@/components/blocks/markdown-renderer";
import { DynamicHeight } from "@/components/ui/DynamicHeight";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { cn } from "@/lib/utils";
import { Reasoning } from "./Reasoning";
import { ThirdwebMiniLogo } from "../../../app/(app)/components/ThirdwebMiniLogo";
import { SupportTicketForm } from "../../../app/(app)/team/[team_slug]/(team)/~/support/_components/SupportTicketForm";
import { Button } from "../ui/button";
import { TextShimmer } from "../ui/text-shimmer";
// Define local types
export type UserMessageContent = { type: "text"; text: string };
@@ -46,11 +57,18 @@ export function CustomChats(props: {
enableAutoScroll: boolean;
useSmallText?: boolean;
sendMessage: (message: UserMessage) => void;
onFeedback?: (messageIndex: number, feedback: 1 | -1) => void;
onFeedback?: (messageIndex: number, feedback: 1 | -1) => Promise<void>;
showSupportForm: boolean;
setShowSupportForm: (v: boolean) => void;
productLabel: string;
setProductLabel: (v: string) => void;
team: Team;
addSuccessMessage?: (message: string) => void;
}) {
const { messages, setEnableAutoScroll, enableAutoScroll } = props;
const scrollAnchorRef = useRef<HTMLDivElement>(null);
const chatContainerRef = useRef<HTMLDivElement>(null);
const [supportTicketCreated, setSupportTicketCreated] = useState(false);
// auto scroll to bottom when messages change
// eslint-disable-next-line no-restricted-syntax
@@ -86,6 +104,8 @@ export function CustomChats(props: {
chatScrollContainer.addEventListener("wheel", disableScroll);
}, [setEnableAutoScroll, enableAutoScroll]);
const [showSupportFormDialog, setShowSupportFormDialog] = useState(false);
return (
<div
className="relative flex max-h-full flex-1 flex-col overflow-hidden"
@@ -123,6 +143,66 @@ export function CustomChats(props: {
sendMessage={props.sendMessage}
sessionId={props.sessionId}
/>
{/* Support Case Button/Form in last assistant message */}
{message.type === "assistant" &&
index === props.messages.length - 1 && (
<>
{/* Only show button/form if ticket not created */}
{!supportTicketCreated && (
<div className="mt-3 pl-12">
<Dialog
open={showSupportFormDialog}
onOpenChange={setShowSupportFormDialog}
>
<Button
onClick={() => setShowSupportFormDialog(true)}
size="sm"
variant="outline"
className="rounded-full bg-card"
>
Create Support Case
<ArrowRightIcon className="w-4 h-4 ml-2" />
</Button>
<DialogContent className="p-0 bg-card">
<DynamicHeight>
<DialogHeader className="p-4 lg:p-6 border-b border-dashed space-y-1">
<DialogTitle className="text-xl font-semibold text-foreground tracking-tight">
Create Support Case
</DialogTitle>
<p className="text-muted-foreground text-sm">
Let's create a detailed support case for
our technical team.
</p>
</DialogHeader>
<SupportTicketForm
team={props.team}
productLabel={props.productLabel}
setProductLabel={props.setProductLabel}
conversationId={props.sessionId}
closeForm={() => {
setShowSupportFormDialog(false);
}}
onSuccess={() => {
props.setShowSupportForm(false);
props.setProductLabel("");
setSupportTicketCreated(true);
// Add success message as a regular assistant message
if (props.addSuccessMessage) {
const supportPortalUrl = `/team/${props.team.slug}/~/support`;
props.addSuccessMessage(
`Your support ticket has been created! Our team will get back to you soon. You can also visit the [support portal](${supportPortalUrl}) to track your case.`,
);
}
}}
/>
</DynamicHeight>
</DialogContent>
</Dialog>
</div>
)}
</>
)}
</div>
);
})}
@@ -143,7 +223,7 @@ function RenderMessage(props: {
nextMessage: CustomChatMessage | undefined;
authToken: string;
sessionId: string | undefined;
onFeedback?: (messageIndex: number, feedback: 1 | -1) => void;
onFeedback?: (messageIndex: number, feedback: 1 | -1) => Promise<void>;
}) {
const { message } = props;
@@ -179,13 +259,16 @@ function RenderMessage(props: {
<div
className={cn(
"flex size-9 items-center justify-center rounded-full",
message.type === "assistant" && "border bg-card",
message.type === "assistant" && "border bg-inverted",
message.type === "error" && "border",
message.type === "presence" && "border bg-card",
message.type === "presence" && "border bg-inverted",
)}
>
{(message.type === "presence" || message.type === "assistant") && (
<MessageCircleIcon className="size-5 text-muted-foreground" />
<ThirdwebMiniLogo
className="size-4 text-inverted-foreground"
isMonoChrome
/>
)}
{message.type === "error" && (
@@ -227,7 +310,7 @@ function RenderMessage(props: {
function CustomFeedbackButtons(props: {
message: CustomChatMessage & { type: "assistant" };
messageIndex: number;
onFeedback: (messageIndex: number, feedback: 1 | -1) => void;
onFeedback: (messageIndex: number, feedback: 1 | -1) => Promise<void>;
className?: string;
}) {
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -240,9 +323,9 @@ function CustomFeedbackButtons(props: {
await props.onFeedback(props.messageIndex, feedback);
} catch (_e) {
// Handle error silently
} finally {
setIsSubmitting(false);
}
setIsSubmitting(false);
};
// Don't show buttons if feedback already given
@@ -251,25 +334,26 @@ function CustomFeedbackButtons(props: {
}
return (
<div className={cn("flex gap-2", props.className)}>
<button
aria-label="Thumbs up"
className="text-muted-foreground transition-colors hover:text-green-500 disabled:opacity-50"
<div className={cn("flex gap-1.5", props.className)}>
<Button
aria-label="Upvote"
variant="outline"
disabled={isSubmitting}
onClick={() => handleFeedback(1)}
type="button"
className="size-8 p-0 rounded-lg bg-card"
>
<ThumbsUpIcon className="size-5" />
</button>
<button
aria-label="Thumbs down"
className="text-muted-foreground transition-colors hover:text-red-500 disabled:opacity-50"
<ThumbsUpIcon className="size-3.5" />
</Button>
<Button
aria-label="Downvote"
variant="outline"
disabled={isSubmitting}
onClick={() => handleFeedback(-1)}
type="button"
className="size-8 p-0 rounded-lg bg-card"
>
<ThumbsDownIcon className="size-5" />
</button>
<ThumbsDownIcon className="size-3.5" />
</Button>
</div>
);
}
@@ -296,7 +380,11 @@ function RenderResponse(props: {
);
case "presence":
return <Reasoning isPending={isMessagePending} texts={message.texts} />;
return (
<div className="h-8 flex items-center">
<TextShimmer text="Reasoning..." />
</div>
);
case "error":
return (
@@ -325,19 +413,15 @@ function StyledMarkdownRenderer(props: {
}) {
return (
<MarkdownRenderer
className="text-foreground [&>*:first-child]:mt-0 [&>*:first-child]:border-none [&>*:first-child]:pb-0 [&>*:last-child]:mb-0"
className="[&>*:first-child]:mt-0 [&>*:first-child]:border-none [&>*:first-child]:pb-0 [&>*:last-child]:mb-0"
code={{
className: "bg-transparent",
className: "bg-card",
ignoreFormattingErrors: true,
}}
inlineCode={{ className: "border-none" }}
li={{ className: "text-foreground" }}
markdownText={props.text}
p={{
className:
props.type === "assistant"
? "text-foreground"
: "text-foreground leading-normal",
className: props.type === "assistant" ? "" : "leading-normal",
}}
skipHtml
/>
@@ -1,62 +0,0 @@
import { ChevronDownIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { DynamicHeight } from "@/components/ui/DynamicHeight";
import { TextShimmer } from "@/components/ui/text-shimmer";
import { cn } from "@/lib/utils";
export function Reasoning(props: { isPending: boolean; texts: string[] }) {
const [_isOpen, setIsOpen] = useState(false);
const isOpen = props.isPending ? true : _isOpen;
const showAll = !props.isPending;
const lastText = props.texts[props.texts.length - 1];
return (
<DynamicHeight>
<Button
className="h-auto w-auto items-center gap-1 px-0 py-1 pb-2 font-normal text-base text-muted-foreground hover:text-foreground hover:no-underline"
onClick={() => setIsOpen(!isOpen)}
size="sm"
variant="link"
>
{props.isPending ? (
<TextShimmer text="Reasoning..." />
) : (
<span className="text-foreground">Reasoning</span>
)}
{!props.isPending && (
<ChevronDownIcon
className={cn(
"size-4 transition-transform",
isOpen && "rotate-180",
)}
/>
)}
</Button>
{isOpen && (
<>
{showAll && props.texts.length > 0 && (
<ul className="list-none space-y-1.5">
{props.texts.map((text) => (
<li
className="fade-in-0 animate-in text-muted-foreground text-sm leading-relaxed duration-300"
key={text}
>
{text.trim()}
</li>
))}
</ul>
)}
{!showAll && lastText && (
<div className="text-muted-foreground text-sm leading-relaxed">
{lastText.trim()}
</div>
)}
</>
)}
</DynamicHeight>
);
}
@@ -6,12 +6,6 @@ export type ExamplePrompt = {
// TODO - remove "Nebula" wording and simplify types
export type NebulaContext = {
chainIds: string[] | null;
walletAddress: string | null;
networks: "mainnet" | "testnet" | "all" | null;
};
type NebulaUserMessageContentItem =
| {
type: "image";
@@ -1,7 +1,5 @@
"use client";
import { useFavoriteChainIds } from "@app/(dashboard)/(chain)/components/client/star-button";
import { doLogout } from "@app/login/auth-actions";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
@@ -14,12 +12,14 @@ import {
useActiveAccount,
useConnectModal,
} from "thirdweb/react";
import { doLogout } from "@/actions/auth-actions";
import { resetAnalytics } from "@/analytics/reset";
import { CustomChainRenderer } from "@/components/misc/CustomChainRenderer";
import { LazyConfigureNetworkModal } from "@/components/misc/configure-networks/LazyConfigureNetworkModal";
import { Button } from "@/components/ui/button";
import { popularChains } from "@/constants/popularChains";
import { useAllChainsData } from "@/hooks/chains/allChains";
import { useFavoriteChainIds } from "@/hooks/favorite-chains";
import { useStore } from "@/lib/reactive";
import {
addRecentlyUsedChainId,
@@ -1,49 +0,0 @@
import type { Abi } from "abitype";
import { Select } from "chakra-react-select";
import { useMemo } from "react";
interface AbiSelectorProps {
abi: Abi;
defaultValue: string;
value: string;
onChange: (fn: string) => void;
}
export const AbiSelector: React.FC<AbiSelectorProps> = ({
abi,
value,
defaultValue,
onChange,
}) => {
const options = useMemo(() => {
return abi
.filter((f) => f.type === "function")
.filter((f) => f.stateMutability !== "view")
.map((f) => ({
label: f.name,
value: f.name,
}));
}, [abi]);
return (
<div className="flex w-full flex-row items-center gap-2">
<Select
chakraStyles={{
container: (provided) => ({
...provided,
width: "full",
}),
}}
defaultValue={options.find((o) => o.value === defaultValue)}
onChange={(selectedFn) => {
if (selectedFn) {
onChange((selectedFn as { label: string; value: string }).value);
}
}}
options={options}
placeholder="Select function"
value={options.find((o) => o.value === value)}
/>
</div>
);
};
@@ -1,159 +0,0 @@
import {
Box,
Flex,
FormControl,
IconButton,
Input,
ListItem,
UnorderedList,
} from "@chakra-ui/react";
import type { Abi } from "abitype";
import { Button } from "chakra/button";
import { Heading } from "chakra/heading";
import { Text } from "chakra/text";
import { PlusIcon, TrashIcon } from "lucide-react";
import { type Dispatch, type SetStateAction, useEffect } from "react";
import { Controller, useFieldArray, useFormContext } from "react-hook-form";
import type { ThirdwebClient } from "thirdweb";
import { SingleNetworkSelector } from "@/components/blocks/NetworkSelectors";
import { useCustomFactoryAbi } from "@/hooks/contract-hooks";
import { AbiSelector } from "./abi-selector";
interface CustomFactoryProps {
setCustomFactoryAbi: Dispatch<SetStateAction<Abi>>;
client: ThirdwebClient;
}
export const CustomFactory: React.FC<CustomFactoryProps> = ({
setCustomFactoryAbi,
client,
}) => {
const form = useFormContext();
const customFactoryAbi = useCustomFactoryAbi(
client,
form.watch("customFactoryAddresses[0].value"),
form.watch("customFactoryAddresses[0].key"),
);
// FIXME: all of this logic needs to be reworked
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
if (customFactoryAbi?.data) {
setCustomFactoryAbi(customFactoryAbi.data);
}
}, [customFactoryAbi, setCustomFactoryAbi]);
const { fields, append, remove } = useFieldArray({
control: form.control,
name: "customFactoryAddresses",
});
// FIXME: all of this logic needs to be reworked
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
if (fields.length === 0) {
append({ key: 1, value: "" }, { shouldFocus: false });
}
}, [fields, append]);
return (
<Flex flexDir="column" gap={12} pb={0} px={0}>
<UnorderedList>
<Text as={ListItem}>
Use this if you want to invoke your own function with custom logic
when users deploy your contract.
</Text>
<Text as={ListItem}>
You need to have factory contracts pre-deployed to all networks that
you want to support.
</Text>
</UnorderedList>
<Flex flexDir="column" gap={4}>
<Flex flexDir="column" gap={2}>
<Heading size="title.md">Factory contract addresses</Heading>
<Text>
Paste the contract address of your factory contracts. Your contract
can be deployed only to networks with valid factory address.
</Text>
</Flex>
{fields.map((field, index) => (
<div key={field.id}>
<FormControl as={Flex} gap={4} isRequired>
<Box w={{ base: "full", md: "40%" }}>
<Controller
control={form.control}
name={`customFactoryAddresses[${index}].key`}
render={({ field: _field }) => {
return (
<SingleNetworkSelector
chainId={_field.value}
client={client}
onChange={(value) => {
_field.onChange(value);
}}
/>
);
}}
/>
</Box>
<Box w="full">
<Input
isRequired
{...form.register(`customFactoryAddresses[${index}].value`)}
placeholder="Factory contract address"
/>
</Box>
<IconButton
aria-label="Remove row"
icon={<TrashIcon className="size-5" />}
isDisabled={fields.length === 1 || form.formState.isSubmitting}
onClick={() => remove(index)}
/>
</FormControl>
</div>
))}
<div>
<Button
borderRadius="md"
colorScheme="primary"
leftIcon={<PlusIcon className="size-5" />}
onClick={() => append({ key: "", value: "" })}
size="sm"
type="button"
>
Add Network
</Button>
</div>
</Flex>
<Flex flexDir="column" gap={4}>
<Flex flexDir="column" gap={2}>
<Heading size="title.md">Factory function</Heading>
<Text>Choose the factory function to deploy your contracts.</Text>
</Flex>
<FormControl isRequired>
{customFactoryAbi?.data ? (
<AbiSelector
abi={customFactoryAbi.data}
defaultValue="deployProxyByImplementation"
onChange={(selectedFn) =>
form.setValue(
"factoryDeploymentData.customFactoryInput.factoryFunction",
selectedFn,
)
}
value={form.watch(
"factoryDeploymentData.customFactoryInput.factoryFunction",
)}
/>
) : (
<Text fontStyle="italic">
Custom factory ABI not found. Please provide a valid imported
contract on the previous step.
</Text>
)}
</FormControl>
</Flex>
</Flex>
);
};
@@ -1,75 +0,0 @@
import { Flex, FormControl, ListItem, UnorderedList } from "@chakra-ui/react";
import type { Abi } from "abitype";
import { Heading } from "chakra/heading";
import { Link } from "chakra/link";
import { Text } from "chakra/text";
import { useFormContext } from "react-hook-form";
import type { ThirdwebClient } from "thirdweb";
import { AbiSelector } from "./abi-selector";
import { NetworksFieldset } from "./networks-fieldset";
interface DefaultFactoryProps {
abi: Abi;
client: ThirdwebClient;
}
export const DefaultFactory: React.FC<DefaultFactoryProps> = ({
abi,
client,
}) => {
const form = useFormContext();
return (
<Flex flexDir="column" gap={12} pb={0} px={0}>
<UnorderedList>
<Text as={ListItem}>
Default factory lets users deploy your contract to{" "}
<strong>any EVM network</strong>.
</Text>
<Text as={ListItem}>
The factory deploys EIP-1167 minimal proxies of your contract. This
makes it much cheaper to deploy.
</Text>
<Text as={ListItem}>
The factory is{" "}
<Link
color="primary.500"
href="https://github.com/thirdweb-dev/contracts/blob/main/contracts/TWStatelessFactory.sol"
isExternal
>
open-source
</Link>
, permissionless, and does not alter contract ownership.
</Text>
<Text as={ListItem}>
Your contract needs to be written in the upgradeable/initializable
pattern. It needs to contain an initializer function.
</Text>
</UnorderedList>
<Flex flexDir="column" gap={4}>
<Flex flexDir="column" gap={2}>
<Heading size="title.md">Initializer function</Heading>
<Text>
Choose the initializer function to invoke on your proxy contracts.
</Text>
</Flex>
<FormControl isRequired>
<AbiSelector
abi={abi}
defaultValue="initialize"
onChange={(selectedFn) =>
form.setValue(
"factoryDeploymentData.implementationInitializerFunction",
selectedFn,
)
}
value={form.watch(
"factoryDeploymentData.implementationInitializerFunction",
)}
/>
</FormControl>
</Flex>
<NetworksFieldset client={client} />
</Flex>
);
};
@@ -1,84 +0,0 @@
import { TrashIcon } from "lucide-react";
import { useFormContext } from "react-hook-form";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
interface ExternalLinksInputProps {
index: number;
remove: (index: number) => void;
}
export const ExternalLinksInput: React.FC<ExternalLinksInputProps> = ({
index,
remove,
}) => {
const form = useFormContext();
return (
<div className="flex flex-col gap-2">
<div className="flex w-full flex-col gap-4 md:flex-row md:gap-2">
<div className="flex flex-1 flex-col gap-1">
<Label className="capitalize" htmlFor={`externalLinks.${index}.name`}>
Resource Name
</Label>
<Input
id={`externalLinks.${index}.name`}
placeholder="Resource name"
{...form.register(`externalLinks.${index}.name`)}
/>
{form.getFieldState(`externalLinks.${index}.name`, form.formState)
.error?.message && (
<p className="text-destructive-text text-sm">
{
form.getFieldState(
`externalLinks.${index}.name`,
form.formState,
).error?.message
}
</p>
)}
</div>
<div className="flex flex-1 flex-col gap-1">
<Label className="capitalize" htmlFor={`externalLinks.${index}.url`}>
Link
</Label>
<Input
id={`externalLinks.${index}.url`}
placeholder="Provide URL to the resource page"
{...form.register(`externalLinks.${index}.url`, {
required: true,
validate: (value: string) => {
if (value.match(new RegExp(/^https:\/\/[^\s/$.?#].[^\s]*$/))) {
return true;
}
return "Provide a valid URL";
},
})}
/>
{form.getFieldState(`externalLinks.${index}.url`, form.formState)
.error?.message && (
<p className="text-destructive-text text-sm">
{
form.getFieldState(`externalLinks.${index}.url`, form.formState)
.error?.message
}
</p>
)}
</div>
<Button
aria-label="Remove row"
className="self-end"
onClick={() => remove(index)}
size="icon"
variant="ghost"
>
<TrashIcon className="size-5" />
<span className="sr-only">Remove row</span>
</Button>
</div>
<Separator />
</div>
);
};
@@ -1,66 +0,0 @@
import { ButtonGroup, Flex } from "@chakra-ui/react";
import type { Abi } from "abitype";
import { Button } from "chakra/button";
import { Heading } from "chakra/heading";
import type { Dispatch, SetStateAction } from "react";
import { useFormContext } from "react-hook-form";
import type { ThirdwebClient } from "thirdweb";
import { CustomFactory } from "./custom-factory";
import { DefaultFactory } from "./default-factory";
interface FactoryFieldsetProps {
abi: Abi;
setCustomFactoryAbi: Dispatch<SetStateAction<Abi>>;
client: ThirdwebClient;
}
export const FactoryFieldset: React.FC<FactoryFieldsetProps> = ({
abi,
setCustomFactoryAbi,
client,
}) => {
const form = useFormContext();
return (
<Flex as="fieldset" direction="column" gap={12}>
<Flex direction="column" gap={6}>
<Heading size="title.lg">Factory deploy settings</Heading>
<ButtonGroup size="sm" spacing={{ base: 0.5, md: 2 }} variant="ghost">
<Button
_active={{
bg: "bgBlack",
color: "bgWhite",
}}
isActive={form.watch("deployType") === "autoFactory"}
onClick={() => form.setValue("deployType", "autoFactory")}
rounded="lg"
type="button"
>
Default Factory
</Button>
<Button
_active={{
bg: "bgBlack",
color: "bgWhite",
}}
isActive={form.watch("deployType") === "customFactory"}
onClick={() => form.setValue("deployType", "customFactory")}
rounded="lg"
type="button"
>
Custom Factory (Advanced)
</Button>
</ButtonGroup>
{form.watch("deployType") === "autoFactory" && (
<DefaultFactory abi={abi} client={client} />
)}
{form.watch("deployType") === "customFactory" && (
<CustomFactory
client={client}
setCustomFactoryAbi={setCustomFactoryAbi}
/>
)}
</Flex>
</Flex>
);
};
@@ -1,466 +0,0 @@
"use client";
import { Box, Divider, Flex, IconButton } from "@chakra-ui/react";
import type { Abi } from "abitype";
import { Button } from "chakra/button";
import { Text } from "chakra/text";
import { ChevronFirstIcon } from "lucide-react";
import { useId, useMemo, useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import type { ThirdwebClient } from "thirdweb";
import type { FetchDeployMetadataResult } from "thirdweb/contract";
import {
getContractPublisher,
publishContract,
} from "thirdweb/extensions/thirdweb";
import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react";
import { reportContractPublished } from "@/analytics/report";
import { CustomConnectWallet } from "@/components/connect-wallet";
import {
DASHBOARD_ENGINE_RELAYER_URL,
DASHBOARD_FORWARDER_ADDRESS,
} from "@/constants/misc";
import { useEns, useFunctionParamsFromABI } from "@/hooks/contract-hooks";
import { useTxNotifications } from "@/hooks/useTxNotifications";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect";
import { ContractParamsFieldset } from "./contract-params-fieldset";
import { FactoryFieldset } from "./factory-fieldset";
import { ImplementationParamsFieldset } from "./impl-params-fieldset";
import { LandingFieldset } from "./landing-fieldset";
import { NetworksFieldset } from "./networks-fieldset";
export function ContractPublishForm(props: {
publishMetadata: FetchDeployMetadataResult;
onPublishSuccess: () => Promise<void>;
isLoggedIn: boolean;
client: ThirdwebClient;
}) {
const [customFactoryAbi, setCustomFactoryAbi] = useState<Abi>([]);
const [fieldsetToShow, setFieldsetToShow] = useState<
"landing" | "factory" | "contractParams" | "implParams" | "networks"
>("landing");
const router = useDashboardRouter();
const { onSuccess, onError } = useTxNotifications(
"Successfully published contract",
"Failed to publish contract",
);
const account = useActiveAccount();
const sendTx = useSendAndConfirmTransaction({
gasless: {
experimentalChainlessSupport: true,
provider: "engine",
relayerForwarderAddress: DASHBOARD_FORWARDER_ADDRESS,
relayerUrl: DASHBOARD_ENGINE_RELAYER_URL,
},
});
const latestVersion = props.publishMetadata.version;
const placeholderVersion = useMemo(() => {
if (latestVersion) {
const versionSplit = latestVersion.split(".");
return `${versionSplit[0]}.${versionSplit[1]}.${Number(versionSplit[2]) + 1 || 0}`;
}
return "1.0.0";
}, [latestVersion]);
const transformedQueryData = useMemo(() => {
return {
...props.publishMetadata,
changelog: "",
constructorParams: props.publishMetadata.constructorParams || {},
customFactoryAddresses: Object.entries(
props.publishMetadata.factoryDeploymentData?.customFactoryInput
?.customFactoryAddresses || {},
).map(([key, value]) => ({ key: Number(key), value })),
defaultExtensions: props.publishMetadata.defaultExtensions || [],
defaultModules: props.publishMetadata.defaultModules || [],
deployType: props.publishMetadata.deployType || "standard",
description:
props.publishMetadata.description ||
props.publishMetadata.info?.notice ||
"",
displayName:
props.publishMetadata.displayName ||
props.publishMetadata.info?.title ||
props.publishMetadata.name ||
"",
extensionsParamName:
props.publishMetadata.factoryDeploymentData?.modularFactoryInput
?.hooksParamName || "",
factoryDeploymentData: props.publishMetadata?.factoryDeploymentData || {
customFactoryInput: {
customFactoryAddresses:
props.publishMetadata.factoryDeploymentData?.customFactoryInput
?.customFactoryAddresses || {},
factoryFunction:
props.publishMetadata.factoryDeploymentData?.customFactoryInput
?.factoryFunction || "deployProxyByImplementation",
params:
props.publishMetadata.factoryDeploymentData?.customFactoryInput
?.params || [],
},
factoryAddresses: {},
implementationAddresses: {},
implementationInitializerFunction: "initialize",
},
implConstructorParams: props.publishMetadata.implConstructorParams || {},
name: props.publishMetadata.name || "",
networksForDeployment: props.publishMetadata?.networksForDeployment || {
allNetworks: true,
},
version: placeholderVersion,
};
}, [placeholderVersion, props.publishMetadata]);
const form = useForm<
FetchDeployMetadataResult & { name: string; version: string }
>({
defaultValues: transformedQueryData,
resetOptions: {
keepDirty: true,
keepDirtyValues: true,
},
values: transformedQueryData,
});
const disableNext =
!form.watch("version") ||
!form.watch("displayName") ||
!!form.getFieldState("version", form.formState).error;
const ensQuery = useEns({
addressOrEnsName: account?.address,
client: props.client,
});
const ensNameOrAddress = useMemo(() => {
return ensQuery?.data?.ensName || ensQuery.data?.address;
}, [ensQuery.data]);
const successRedirectUrl = useMemo(() => {
if (!ensNameOrAddress || !props.publishMetadata.name) {
return undefined;
}
return `/${ensNameOrAddress}/${props.publishMetadata.name}`;
}, [ensNameOrAddress, props.publishMetadata.name]);
const isDisabled = useMemo(
() => !successRedirectUrl || !account,
[successRedirectUrl, account],
);
const constructorParams =
props.publishMetadata.abi.find((c) => c.type === "constructor")?.inputs ||
[];
const initializerParams = useFunctionParamsFromABI(
form.watch("deployType") === "customFactory"
? customFactoryAbi
: props.publishMetadata.abi,
form.watch("deployType") === "customFactory"
? form.watch(
"factoryDeploymentData.customFactoryInput.factoryFunction",
) ||
props.publishMetadata.factoryDeploymentData?.customFactoryInput
?.factoryFunction ||
"deployProxyByImplementation"
: form.watch("factoryDeploymentData.implementationInitializerFunction") ||
props.publishMetadata.factoryDeploymentData
?.implementationInitializerFunction ||
"initialize",
);
const deployParams =
form.watch("deployType") === "standard"
? constructorParams
: initializerParams;
const implDeployParams =
form.watch("deployType") === "autoFactory" ? constructorParams : [];
// during loading and after success we should stay in loading state
const isPending = sendTx.isPending || sendTx.isSuccess;
useIsomorphicLayoutEffect(() => {
window?.scrollTo({
behavior: "smooth",
top: 0,
});
}, []);
const formId = useId();
return (
<FormProvider {...form}>
<div className="w-full">
<Flex
as="form"
direction="column"
gap={6}
id={formId}
onSubmit={form.handleSubmit((data) => {
if (!account) {
// no account, do nothing
return;
}
const addressArray =
Object.keys(data?.customFactoryAddresses || {}).length > 0
? (data?.customFactoryAddresses as unknown as {
key: number;
value: string;
}[])
: [];
const addressObj = addressArray.reduce<Record<number, string>>(
(obj, item) => {
obj[item.key] = item.value;
return obj;
},
{},
);
const metadata = {
...data,
factoryDeploymentData: {
...data.factoryDeploymentData,
customFactoryInput: {
customFactoryAddresses:
addressObj ||
data.factoryDeploymentData?.customFactoryInput
?.customFactoryAddresses,
factoryFunction:
data.factoryDeploymentData?.customFactoryInput
?.factoryFunction || "deployProxyByImplementation",
params:
data.factoryDeploymentData?.customFactoryInput?.params ||
[],
},
implementationAddresses:
data.factoryDeploymentData?.implementationAddresses || {},
implementationInitializerFunction:
data.factoryDeploymentData
?.implementationInitializerFunction || "initialize",
},
networksForDeployment: {
allNetworks:
data.deployType === "customFactory"
? false
: data.networksForDeployment?.allNetworks,
networksEnabled:
addressArray.length > 0
? Object.keys(addressObj).map((val) => Number(val))
: data.networksForDeployment?.networksEnabled,
},
} satisfies FetchDeployMetadataResult & {
name: string;
version: string;
};
const tx = publishContract({
account,
contract: getContractPublisher(props.client),
metadata,
previousMetadata: props.publishMetadata,
});
sendTx.mutate(tx, {
onError: (err) => {
console.error("Failed to publish contract", err);
onError(err);
},
onSuccess: async () => {
onSuccess();
reportContractPublished({
contractName: props.publishMetadata.name,
deployType: data.deployType,
publisher: ensNameOrAddress ?? "",
version: data.version,
});
await props.onPublishSuccess().catch((err) => {
console.error("Failed to run onPublishSuccess", err);
});
if (successRedirectUrl) {
router.push(successRedirectUrl, { scroll: true });
}
},
});
})}
>
{fieldsetToShow !== "landing" && (
<div>
<IconButton
aria-label="Back"
icon={<ChevronFirstIcon className="size-6" />}
onClick={() =>
fieldsetToShow === "contractParams" &&
(form.watch("deployType") === "autoFactory" ||
form.watch("deployType") === "customFactory")
? setFieldsetToShow("factory")
: fieldsetToShow === "contractParams" &&
form.watch("deployType") === "standard"
? setFieldsetToShow("networks")
: fieldsetToShow === "implParams"
? setFieldsetToShow("contractParams")
: setFieldsetToShow("landing")
}
variant="ghost"
w="inherit"
>
Back
</IconButton>
</div>
)}
{fieldsetToShow === "landing" && (
<LandingFieldset
client={props.client}
latestVersion={latestVersion}
placeholderVersion={placeholderVersion}
/>
)}
{fieldsetToShow === "contractParams" && (
<ContractParamsFieldset
client={props.client}
deployParams={deployParams}
/>
)}
{fieldsetToShow === "implParams" && implDeployParams?.length > 0 && (
<ImplementationParamsFieldset
client={props.client}
implParams={implDeployParams}
/>
)}
{fieldsetToShow === "factory" && (
<Flex flexDir="column" gap={24}>
<FactoryFieldset
abi={props.publishMetadata.abi || []}
client={props.client}
setCustomFactoryAbi={setCustomFactoryAbi}
/>
</Flex>
)}
{fieldsetToShow === "networks" && (
<Flex flexDir="column" gap={24}>
<NetworksFieldset client={props.client} fromStandard />
</Flex>
)}
<Flex flexDir="column" gap={6}>
<Divider />
<Flex
alignItems="center"
flexDir={{ base: "column", md: "row" }}
gap={4}
justifyContent="space-between"
>
{!account ? (
<>
<Box />
<CustomConnectWallet
client={props.client}
isLoggedIn={props.isLoggedIn}
/>
</>
) : fieldsetToShow === "landing" &&
form.watch("deployType") === "standard" ? (
<>
<Box />
<Button
colorScheme="primary"
isDisabled={disableNext}
onClick={() => setFieldsetToShow("networks")}
>
Next
</Button>
</>
) : fieldsetToShow === "landing" &&
(form.watch("deployType") === "autoFactory" ||
form.watch("deployType") === "customFactory") ? (
<>
<Box />
<Button
colorScheme="primary"
isDisabled={disableNext}
onClick={() => setFieldsetToShow("factory")}
>
Next
</Button>
</>
) : fieldsetToShow !== "contractParams" &&
fieldsetToShow !== "implParams" &&
deployParams?.length > 0 ? (
<>
<Box />
<Button
colorScheme="primary"
isDisabled={disableNext}
onClick={() => setFieldsetToShow("contractParams")}
>
Next
</Button>
</>
) : fieldsetToShow !== "contractParams" &&
fieldsetToShow !== "implParams" &&
deployParams?.length === 0 &&
implDeployParams?.length > 0 ? (
<>
<Box />
<Button
colorScheme="primary"
isDisabled={disableNext}
onClick={() => setFieldsetToShow("implParams")}
>
Next
</Button>
</>
) : fieldsetToShow === "contractParams" &&
implDeployParams?.length > 0 ? (
<>
<Box />
<Button
colorScheme="primary"
isDisabled={disableNext}
onClick={() => setFieldsetToShow("implParams")}
>
Next
</Button>
</>
) : (
<>
<Text fontStyle="italic">
Publishing your contract is free, we cover all gas costs.
</Text>
<Button
// differentiate this from the edit button
borderRadius="md"
colorScheme="blue"
form={formId}
isDisabled={isDisabled}
isLoading={isPending}
key="submit-button"
loadingText={
sendTx.isSuccess
? "Preparing page"
: "Publishing contract"
}
position="relative"
type="submit"
>
Publish Contract
</Button>
</>
)}
</Flex>
</Flex>
</Flex>
</div>
</FormProvider>
);
}

Some files were not shown because too many files have changed in this diff Show More