Compare commits

..
Author SHA1 Message Date
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
b8f496603c Version Packages (#7967)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-02 16:46:46 -07:00
Joey BrightandGitHub 4c782ad64d docs: Fix Typos in docs (#7963) 2025-09-02 16:46:17 -07:00
gregandGitHub af6a306955 [SDK] Feature: country Code on Payment Widgets (#7966) 2025-09-02 16:44:56 -07:00
MananTank 4b319c353d [BLD-227] Dashboard: Add Button to download snapshot as CSV file in Claim Phase UI (#7965)
<!--

## 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 `ClaimConditionsForm` and enhancing the `ClaimerSelection` component by adjusting imports, improving layout, and adding functionality to download snapshot data as a CSV file.

### Detailed summary
- Removed `ArrowDownToLineIcon` from `ClaimConditionsForm`.
- Updated layout in `ClaimerSelection` to use a flexible column layout.
- Added a button to download snapshots as CSV in `ClaimerSelection`.
- Introduced `downloadSnapshotAsCSV` function to handle CSV generation and downloading.

> ✨ 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 CSV export for Claimer snapshots with a Download button visible when a snapshot exists.

- Style
  - Updated snapshot actions to a responsive layout (stack on small screens, inline on larger screens).
  - Added a distinct Download button with an icon and adjusted Edit button styling.
  - Removed the icon from the Save Phases button, showing text only.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-02 20:57:23 +00:00
saminacodes aadaf209b5 deprecated and redirected docs (#7960)
<!--

## 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 several files related to the `infrastructure` section of the application, including markdown files, images, and TypeScript components, while also updating the `redirects.mjs` file to include new external portal redirects.

### Detailed summary
- Deleted the following files:
  - `apps/portal/src/app/infrastructure/page.mdx`
  - `apps/portal/src/app/infrastructure/layout.tsx`
  - `apps/portal/src/app/infrastructure/sidebar.tsx`
  - `apps/portal/src/app/infrastructure/assets/test.jpg`
  - `apps/portal/src/app/infrastructure/storage/overview/page.mdx`
  - `apps/portal/src/app/infrastructure/rpc-edge/overview/page.mdx`
  - `apps/portal/src/app/infrastructure/rpc-edge/get-started/page.mdx`
  - `apps/portal/src/app/infrastructure/storage/how-storage-works/page.mdx`
  - `apps/portal/src/app/infrastructure/rpc-edge/get-started/assets/api-key.png`
  - `apps/portal/src/app/infrastructure/rpc-edge/overview/assets/rpc-diagram.svg`
  - `apps/portal/src/app/infrastructure/rpc-edge/get-started/assets/public-rpcs.png`
  - `apps/portal/src/app/infrastructure/rpc-edge/get-started/assets/usage-dashboard.png`
  - `apps/portal/src/app/infrastructure/storage/how-to-use-storage/host-web-app/page.mdx`
  - `apps/portal/src/app/infrastructure/storage/how-storage-works/assets/storage-diagram.svg`
  - `apps/portal/src/app/infrastructure/storage/how-to-use-storage/upload-files-to-ipfs/page.mdx`
  - `apps/portal/src/app/infrastructure/storage/how-to-use-storage/upload-files-to-ipfs/assets/storage-urls.png`
  - `apps/portal/src/app/infrastructure/storage/how-to-use-storage/upload-files-to-ipfs/assets/storage-upload.png`
  - `apps/portal/src/app/infrastructure/storage/how-to-use-storage/upload-files-to-ipfs/assets/storage-dashboard.png`
- Updated `apps/portal/redirects.mjs` to:
  - Redirect `"/storage/upload-to-ipfs"` to `"/infrastructure/storage/how-to-use-storage/upload-files-to-ipfs"`
  - Add infrastructure redirects to external portal links for `"/infrastructure/storage/:path*"` and `"/infrastructure/rpc-edge/:path*"`

> ✨ 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
  - Removed the Infrastructure section from the portal, including Overview, Storage (Overview, How Storage Works, Upload Files to IPFS, Host Web App), and RPC Edge (Overview, Get Started) pages.
  - Updated navigation accordingly to reflect the removal of these pages.

- New Features
  - Added automatic redirects for Infrastructure content:
    - /infrastructure/storage/:path* now points to the external Storage documentation.
    - /infrastructure/rpc-edge/:path* now points to the external RPC documentation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-02 16:56:21 +00:00
Joaquim VergesandGitHub df6f8e2646 [Playground] Refactor AI types and move definitions to types.ts (#7964) 2025-09-02 02:05:40 -07:00
5b871ac281 [Portal] docs: fix broken link (#7962)
Signed-off-by: VolodymyrBg <[email protected]>
Signed-off-by: Joaquim Verges <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2025-09-02 20:54:54 +12:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
7eed8e61db Version Packages (#7957)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-01 00:06:04 -07:00
Joaquim VergesandGitHub 6ef2f3b37a [AI SDK Provider] Auto handle session ids (#7956) 2025-08-31 22:10:49 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
596aaa5495 Version Packages (#7949)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-31 16:18:40 -07:00
MananTank 89eeac1f8a Dashboard: Fix footer not sticked to bottom on short contracts page (#7951)
<!--

## 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 layout of the `contract-page-layout.tsx` component by adding a CSS class to the main `div` element for improved styling and structure.

### Detailed summary
- Changed the main `div` element from `<div>` to `<div className="flex flex-col grow">` to apply flexbox layout and allow the element to grow.

> ✨ 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 contract page layout to use a flexible, column-based structure for more consistent spacing.
  * Improves use of available screen space so content expands naturally within the dashboard.
  * Enhances responsiveness across viewports, reducing awkward white space and unnecessary scrolling.
  * Provides more stable alignment between sidebar and main content on contract detail pages.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-30 04:03:07 +00:00
MananTank c331d189bb Dashboard: Remove OP Sponsored badge in Chain selector (#7948)
<!--

## 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 removes the handling of sponsored chains from the `CustomChainRenderer` component, including the related constant and UI elements that indicate whether a chain is sponsored.

### Detailed summary
- Deleted the import of `OPSponsoredChains` from `@/constants/chains`.
- Removed the `isSponsored` variable that checks if a chain is sponsored.
- Eliminated the UI block that displayed "Sponsored" for sponsored chains.

> ✨ 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
  - Removed the Sponsored badge from the chain list, simplifying the chain renderer.
  - Deprecated chains still display a Deprecated badge and remain non-interactive.
  - Clicking non-deprecated chains continues to switch networks; the Configure Network button is unchanged.

- Chores
  - Removed obsolete sponsor-related configuration and references.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-29 18:13:06 +00:00
MananTank f867799301 [MNY-129] Dashboard: Use useSendAndConfirmTx everywhere, Replace createToken with prepareCreateToken (#7947)
<!--

## 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 replacing the usage of `useSendAndConfirmTransaction` with `useSendAndConfirmTx` across various components in the dashboard application, streamlining transaction handling.

### Detailed summary
- Replaced `useSendAndConfirmTransaction` with `useSendAndConfirmTx` in multiple components.
- Updated imports to reflect the new hook in relevant files.
- Modified transaction handling logic to utilize the new hook consistently across the codebase.

> The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Mintable.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Claimable.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/claim-tokens/claim-tokens-ui.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Royalty.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/claim-conditions/claim-conditions-form/index.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/nft/create-nft-page.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx`

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

<!-- end pr-codex -->
2025-08-29 16:25:21 +00:00
MananTank 597431ec1d [MNY-131] Add Pay Modal integration in useSendAndConfirmTransaction hook (#7946)
<!--

## 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 `Pay Modal` integration in the `useSendAndConfirmTransaction` hook, allowing users to handle insufficient funds by prompting them to purchase more. It also renames the hook and updates related components to utilize the new configuration.

### Detailed summary
- Renamed `useSendAndConfirmTransaction` to `useSendAndConfirmTransactionCore`.
- Updated exports to reflect the renaming.
- Added `payModal` configuration to `useSendAndConfirmTransaction`.
- Updated `CreateDirectListingButton`, `ClaimButton`, and `BuyDirectListingButton` to utilize the new `payModal` configuration.
- Enhanced documentation for `useSendAndConfirmTransaction` with usage examples for the `Pay Modal`.

> ✨ 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**
  * Pay Modal integrated into send-and-confirm transaction flows, matching send-only behavior.
  * Prebuilt buttons (Buy Direct Listing, Claim, Create Direct Listing) pass Pay Modal config and auto-fill metadata with sensible fallbacks for smoother top-ups.
  * Pay Modal options are configurable and compatible with gasless workflows.

* **Documentation**
  * Added examples and guidance for configuring the Pay Modal (theme, disabling, and usage).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-29 16:25:20 +00:00
GiselleNessi d5ff9f2f5d feat: add support siwa feedback system for closed support tickets (#7916)
<!--

## 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 feedback system for support tickets, allowing users to submit ratings and comments. It includes API calls for submitting feedback and checking its status, along with UI updates to handle user interactions and display feedback status.

### Detailed summary
- Added `submitSupportFeedback` function to submit feedback.
- Added `checkFeedbackStatus` function to verify if feedback has been submitted.
- Integrated feedback submission UI in `SupportCaseDetails` component.
- Implemented rating selection using stars.
- Added input field for optional feedback comments.
- Displayed loading and error states for feedback status checks.

> ✨ 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**
  * 5‑star rating UI and optional comment for closed support cases, with Send Feedback button, “Checking feedback status…” and sending spinners, disabled send until a rating is chosen, and a thank‑you message after submission.

* **Improvements**
  * Server-backed feedback status check and submission with input validation, 1–5 rating, 1000‑char comment limit, 10s request timeout, and contextual success/error toasts.
  * Accessible star controls with ARIA labels and filled‑star visuals.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-29 15:27:15 +00:00
saminacodes 76694f0cec Update Contracts FAQ (#7930)
<!--

## 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 new information to the `page.mdx` file regarding deployment costs and auditing of thirdweb contracts.

### Detailed summary
- Added a new `Details` section on deployment costs for thirdweb contracts, outlining:
  - Mint fees and primary sales fees for specific contract types.
  - A 2% convenience fee and a 0.5% protocol fee on primary sales.
  - Clarified that fees apply only to prebuilt contracts via the dashboard.
- Included information about thirdweb contracts being audited by third-party firms.

> ✨ 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 an FAQ explaining costs for deploying prebuilt contracts via the dashboard.
  * Clarifies a 2% dashboard deployment fee plus a 0.5% protocol fee (total 2.5%) taken from primary sales.
  * Includes an example payout and lists affected contract categories.
  * Notes that custom or externally deployed contracts are exempt.
  * Specifies fees are deducted in the sale’s currency and placed after the existing FAQ on using thirdweb with existing contracts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-29 01:16:31 +00:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
65a8c39ce0 Version Packages (#7945)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-28 18:15:35 -07:00
Joaquim VergesandGitHub ac3a95ebbb [AI SDK Provider] Fix type inference for tools (#7944) 2025-08-28 18:10:21 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
00ffe3e46e Version Packages (#7943)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-28 15:46:28 -07:00
gregandGitHub 50c6371e1e [SDK] Feature: add ability to exclude token prices from Bridge.tokens (#7942) 2025-08-28 15:22:12 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
93532ecbdc Version Packages (#7932)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-28 15:14:50 -07:00
Joaquim VergesandGitHub f3ad6efcf8 [Package] @thirdweb-dev/ai-sdk-provider (#7922) 2025-08-28 15:08:23 -07:00
MananTank 67616c22b4 [MNY-127] Dashboard: Remove unnecessary server action for fetching token list (#7940)
<!--

## 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 token management in the universal bridge API, including the introduction of a new `TokenMetadata` type and the relocation of the `getUniversalBridgeTokens` function to a new file. It also updates import paths for consistency.

### Detailed summary
- Added `TokenMetadata` type in `apps/dashboard/src/@/api/universal-bridge/types.ts`.
- Updated import path for `getUniversalBridgeTokens` in `apps/dashboard/src/@/hooks/tokens.ts` and `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx`.
- Created `getUniversalBridgeTokens` function in `apps/dashboard/src/@/api/universal-bridge/token-list.ts`.
- Removed old `getUniversalBridgeTokens` function and `TokenMetadata` type from `apps/dashboard/src/@/api/universal-bridge/tokens.ts`.

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

<!-- end pr-codex -->
2025-08-28 21:37:31 +00:00
MananTank 51f7418d1f [MNY-128] Dashboard: UI tweaks in token creation flow (#7939)
<!--

## 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 user interface and error handling in the token and NFT launch processes, as well as refining the layout and component interactions in the distribution section.

### Detailed summary
- Removed `isPending` state checks from token and NFT launch components.
- Updated button layouts to improve user experience in `launch-token.tsx` and `launch-nft.tsx`.
- Changed error message text in `token-distribution.tsx`.
- Added `errorMessage` prop to `StepCard` for better error display.
- Adjusted layout and styling for improved responsiveness and alignment.

> ✨ 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
  - Step headers can now display error messages.
  - Distribution chart moved into the main form flow for clearer visibility.
  - Post-launch actions updated: show “View NFT Collection” or “View Coin” when available; show “Cancel” before completion.

- Refactor
  - Simplified bottom action areas and removed pending-based button disabling for a more predictable flow.

- Style
  - Improved spacing, alignment, and responsiveness in forms.
  - Updated error text to “Token allocation exceeds total supply” for clearer guidance.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-28 21:26:54 +00:00
MananTank dc3df4bc35 [MNY-11] Dashboard: Add ERC20 token selector for starting price in token creation flow (#7933)
<!--

## 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 token creation process by modifying the `onLaunchSuccess` function to accept `CreateAssetFormValues`, updating the way initial tick values are calculated, and improving the token selection interface.

### Detailed summary
- Updated `onLaunchSuccess` in `launch-token.tsx` and `create-token-page.client.tsx` to accept `formValues` and `contractAddress`.
- Modified `getInitialTickValue` to include `tokenAddress`, `chain`, and `client` parameters.
- Added token selection functionality in the `PoolConfig` component using `TokenSelector`.
- Adjusted form validation and pricing logic for token creation.
- Enhanced UI layout in `PoolConfig` for better responsiveness and usability.

> ✨ 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
  - Token selector added to choose paired currency (native or ERC‑20) and a field to specify/select token address for ERC‑20 pools.
  - Bridging on launch is now performed only for ERC‑20 asset pool launches.

- Bug Fixes
  - Starting-price handling improved to account for token decimals and precompute/validate launch pricing.

- Style
  - Responsive layout and spacing refinements for pricing and allocation inputs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-28 22:40:11 +05:30
MananTank 0853872d8d Dashboard: Fix WalletAddress ens image size (#7935)
<!--

## 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 adjusting the size of certain UI components in the `RecentTransfers` and `WalletAddress` sections, ensuring a more consistent design across the dashboard.

### Detailed summary
- In `RecentTransfers.tsx`, removed the `iconClassName` prop from a component.
- In `wallet-address.tsx`, changed the size of a `div` from `size-6` to `size-5`.
- Updated the `CircleSlashIcon` size from `size-6` to `size-5`.
- Added a `fallback` prop to the `Img` component in `WalletAvatar`.
- Changed the `size` of the `Blobbie` component in `WalletAvatar` from `24` to `20`.

> ✨ 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 automatic address-based avatar fallback when a wallet/avatar image isn’t available.

- Style
  - Reduced sizes for the invalid-address badge and zero-address indicator for better visual balance.
  - Adjusted fallback avatar size for improved consistency.
  - Standardized icon sizing in Recent Transfers by removing a custom icon size override.
  - Overall, wallet/address visuals are cleaner and more consistent across the dashboard.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-28 12:14:10 +00:00
gregandGitHub 44e6e115d9 [SDK] Feature: Allow proceeding past first checkout widget page with no wallet (#7937) 2025-08-27 21:16:01 -07:00
gregandGitHub 76cfecb305 [Dashboard] Feature: Update payment success copy on payment page (#7936) 2025-08-27 21:03:12 -07:00
MananTank f33d8f16e2 packages/ui: Add markdown-renderer (#7928)
<!--

## 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 consolidating the `MarkdownRenderer` component across different applications, enhancing code reusability and organization by utilizing shared components from the `@workspace/ui` package. It also updates dependencies and modifies some configurations.

### Detailed summary
- Deleted `plaintext-code.tsx` from `apps/portal/src/components/code/`.
- Updated `knip.json` files to include new dependencies: `react-children-utilities`, `react-markdown`, and `remark-gfm`.
- Simplified export of `CodeClient` in `code.client.tsx`.
- Added `InlineCode` and `UnderlineLink` components in `packages/ui`.
- Refactored `MarkdownRenderer` in `apps/dashboard` to use shared components from `@workspace/ui`.
- Removed redundant imports in `MarkdownRenderer` files across different applications.
- Updated `pnpm-lock.yaml` with new package versions.
- Adjusted class names in `MarkdownRenderer` for consistent styling.

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

<!-- end pr-codex -->
2025-08-27 23:18:35 +00:00
MananTank 5c08c7c17d packages/ui: Add code components (#7927)
<!--

## 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 code related to the `CodeClient` component, improving its structure and imports, while also updating several components to use a new centralized location for code utilities. It removes deprecated files and enhances code organization across the project.

### Detailed summary
- Deleted unused files related to clipboard and code rendering.
- Refactored `CodeClient` to use a centralized import from `@workspace/ui/components/code/code.client`.
- Updated various components to import `CodeClient` and other utilities from the new centralized location.
- Added new `CodeServer` component for server-side rendering of code.
- Improved loading states and error handling in code components.
- Updated component imports across the project to maintain consistency.
- Enhanced `PlainTextCodeBlock` functionality with new props for better customization.
- Removed redundant code and improved overall project structure.

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

<!-- end pr-codex -->
2025-08-27 23:18:35 +00:00
MananTank e20b1dd883 packages/ui: Add breadcrumb, tooltip, table (#7926)
<!--

## 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 adding the `@radix-ui/react-tooltip` package and refactoring the tooltip and breadcrumb components across multiple applications to enhance UI functionality and maintainability.

### Detailed summary
- Added `@radix-ui/react-tooltip` dependency in `package.json`.
- Updated `knip.json` files to include `@radix-ui/react-tooltip` in ignored dependencies.
- Refactored tooltip components in `packages/ui/src/components/tooltip.tsx` to utilize `@radix-ui/react-tooltip`.
- Created new `Breadcrumb` components in `packages/ui/src/components/breadcrumb.tsx`.
- Updated table components in `packages/ui/src/components/table.tsx` to streamline exports and structure.
- Removed redundant tooltip component definitions from multiple applications and replaced them with imports from `@workspace/ui/components/tooltip`.

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

<!-- end pr-codex -->
2025-08-27 23:18:35 +00:00
MananTank 55a4728766 packages/ui: Add Spinner, Img (#7925)
<!--

## 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 `Spinner` component across multiple applications by centralizing its import path and removing redundant files. It also introduces a new spinner style in the Tailwind configuration.

### Detailed summary
- Deleted multiple `Spinner.tsx` and `Spinner.module.css` files from various directories.
- Updated imports of `Spinner` to a centralized path: `@workspace/ui/components/spinner`.
- Added new spinner animation styles in `tailwind.config.ts`.
- Updated the `Spinner` component to use Tailwind classes for styling instead of CSS modules.
- Adjusted stories for `Spinner` to reflect the new structure and styles.

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

<!-- end pr-codex -->
2025-08-27 23:18:34 +00:00
MananTank c5ef55e4f6 packages/ui: Add scroll-shadow (#7924)
<!--

## 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 `ScrollShadow` component by consolidating its usage across various applications and removing redundant files. It also enhances the component's styling and functionality.

### Detailed summary
- Deleted multiple `ScrollShadow` component files from various apps.
- Created a new `ScrollShadow` component in `packages/ui/src/components/scroll-shadow.tsx`.
- Updated import paths for `ScrollShadow` in multiple files across the applications.
- Simplified styling by removing CSS module imports and integrating styles directly within the component.
- Added new CSS properties for shadows as inline styles.

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

<!-- end pr-codex -->
2025-08-27 23:18:34 +00:00
MananTank afd1150984 packages/ui: Add storybook, Add Badge, Input (#7923)
<!--

## 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 several updates focused on enhancing the UI components, improving Storybook integration, and updating dependencies. It also refactors some components for better modularity and performance.

### Detailed summary
- Added `class-variance-authority` and updated `tailwindcss-animate` in `knip.json`.
- Updated `tailwind.config.ts` to include `.storybook` directory in content.
- Refactored imports for `Button` and `Input` components.
- Created `Badge` component and its variants in `badge.tsx`.
- Updated Storybook configuration in `.storybook/main.ts` and `preview.tsx`.
- Refactored `Input` components in multiple locations to use a shared implementation.
- Added `Toaster` setup in Storybook preview for better notifications.
- Updated dependencies in `package.json` and `pnpm-lock.yaml`.

> ✨ 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**
  - Shared Badge and Input components added to the UI package and made available to apps.
  - Themed Storybook for the UI library with mobile viewports, notifications, data-fetching context, and an in-app theme toggle.

- **Refactor**
  - Apps now re-export Badge/Input from the shared UI package; story utilities and preview/layout centralized.

- **Chores**
  - Storybook script and dependencies added, Tailwind content updated, and import paths standardized.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-27 23:18:33 +00:00
gregandGitHub f79672ebbf [Dashboard]: Fix: Remove in-app wallet connection option on payment page (#7934) 2025-08-27 16:00:13 -07:00
MananTank 3a289e80d1 Dashboard: Fix token not added to UB on launch success (#7931)
<!--

## 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 the `contractAddress` state in the `LaunchTokenStatus` component by using a `ref` to avoid stale closures and ensure the latest address is used during execution.

### Detailed summary
- Added `useCallback` and `useRef` imports.
- Replaced the state setter for `contractAddress` with a callback to update a `ref`.
- Updated the condition to check `contractAddressRef.current` instead of `contractAddress` when launching.

> ✨ 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 the token launch flow so the final confirmation consistently uses the latest deployed contract address.
  - Prevents rare cases where an outdated address could be shown or used after deployment, reducing intermittent post-launch errors.
  - Fix applies to ERC20 and Drop ERC20 deployments; no visible UI changes, just more consistent launches and confirmations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-27 18:54:33 +00:00
Jonas DanielsandGitHub e9efebaec4 Always show Engine in sidebar regardless of instances (#7929) 2025-08-27 11:53:25 -07:00
Jonas DanielsandGitHub d4a44f5b5f Add reason code type to team capabilities response (#7921) 2025-08-27 11:46:02 -07:00
MananTank e651d0ae91 Dashboard: Update Project header style (#7920)
<!--

## 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 updating UI components across various files in the application. It includes adjustments to icon sizes, component styles, and the introduction of new icons, enhancing the overall user interface and experience.

### Detailed summary
- Changed `PlusIcon` size from `size-4` to `size-3.5` in multiple buttons.
- Replaced `SettingsIcon` with `Settings2Icon`.
- Added `DatabaseIcon`, `WebhookIcon`, `TokenIcon`, `ArrowDownToLineIcon`, and others to various headers.
- Updated button styles to `bg-card` and changed variants to `outline`.
- Modified header layouts to include new icons and adjusted spacing.
- Removed actions from several `ProjectPage` components and replaced them with links.
- Adjusted descriptions and added new links in the `ContractsPage`, `PaymentsPage`, and other 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
  - Header icons added across many pages; Settings now appears as a dedicated header control where provided.
  - Single link renders as a direct action button; multiple links grouped under a labeled "Resources" menu with chevron.

- Refactor
  - Project header redesigned to an icon-driven layout; mobile-specific branching removed and actions reorganized.

- Style
  - Button variants, spacing, iconography, and dropdown alignment adjusted (smaller icons, new arrow/chevron visuals, reduced item padding).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-26 22:35:44 +00:00
Joaquim VergesandGitHub 34239ea2cb [Docs] Rename Chat API to Blockchain LLM and add transaction execution docs (#7904) 2025-08-26 03:49:59 -07:00
MananTank 8828df0a58 Dashboard: Fix project links footer not sticked to the bottom on short pages (#7909)
<!--

## 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 layout of the `ProjectPage` component by modifying the class names of certain `div` elements to improve styling and spacing.

### Detailed summary
- Changed the class name of the main `div` from `pb-20` to `grow`.
- Added a new `div` with class `h-20` to provide spacing.
- Updated the class name of the footer `div` from `mt-20` to `mt-auto` for better positioning.

> ✨ 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 project page layout for more consistent spacing and alignment.
  - Standardized vertical spacing and removed conditional bottom padding to ensure predictable layout across views.
  - Footer now aligns to the bottom with automatic spacing, improving visual balance on longer pages.
  - Added a vertical spacer to separate main content from the footer for clearer hierarchy and readability.
  - No changes to public APIs or functionality; visual/spacing adjustments only.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-26 00:59:42 +00:00
MananTank c6150be299 Dashboard: Create Payment link dialog fixes/ui tweaks (#7908)
<!--

## 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 `CreatePaymentLinkButton` component to enhance its dialog interface and improve the overall user experience. It replaces the `LinkIcon` with a `PlusIcon`, refines form elements, and cleans up unused code.

### Detailed summary
- Replaced `LinkIcon` with `PlusIcon`.
- Updated dialog structure and content.
- Changed `RequiredFormLabel` to `FormLabel` for consistency.
- Improved styling by adding `bg-card` class to input fields.
- Removed commented-out code related to image upload functionality.
- Enhanced form layout and submission 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

- **Refactor**
  - Streamlined the payment link creation flow with a clearer dialog and improved form handling for a smoother experience.

- **Style**
  - Updated to a plus icon, added a header with title and description, standardized labels, themed inputs, and introduced a bottom action bar.

- **Bug Fixes**
  - Chain and token changes now properly reset related fields.
  - Improved validation for recipient address and token selection.
  - Added progress indicator during creation.
  - Success toast and automatic refresh ensure newly created payment links appear immediately.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-25 20:37:52 +00:00
MananTank 27f50a863c [BLD-143] Dashboard: Fix distribute funds in split contract (#7907)
<!--

## 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 `useSplitDistributeFunds` hook and the `DistributeButton` component by refining the distribution logic and enhancing error handling.

### Detailed summary
- Replaced direct comparison of `currency.name` with a check using `getAddress(currency.tokenAddress)` against `getAddress(NATIVE_TOKEN_ADDRESS)`.
- Added `await` for the promise in the `useSplitDistributeFunds` function.
- Renamed the mutation variable in `DistributeButton` from `mutation` to `distributeFundsMutation`.
- Updated the `distributeFunds` function to use `distributeFundsMutation.mutateAsync()`.
- Adjusted the `isPending` prop in `TransactionButton` to reference `distributeFundsMutation.isPending`.

> ✨ 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
  - Correctly detects and handles the native token during fund distribution, ensuring accurate routing and transaction counts.
  - Ensures each distribution transaction completes before the next begins, reducing partial or overlapping operations.

- Refactor
  - Streamlined distribution flow and loading state handling for a more consistent experience.
  - Removed toast-based error pop-ups during distribution; status is reflected via the ongoing operation state.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-25 20:09:45 +00:00
MananTank 157f4b9a19 Dashboard: Chain Infra pages UI improvements (#7906)
<!--

## 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 experience in the `Deploy Infrastructure` section of the application. It refines component styles, enhances breadcrumb navigation, and updates form elements for better accessibility and consistency.

### Detailed summary
- Adjusted spacing in the `InfraServiceCard` component.
- Enhanced typography and layout in various sections.
- Added breadcrumb navigation for better user context.
- Updated the `DeployInfrastructureForm` styles for consistency.
- Improved chain selection interface with better guidance.
- Refined the subscription summary layout.
- Enhanced accessibility features across components.

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

<!-- end pr-codex -->
2025-08-25 17:21:38 +00:00
MananTank fbe1aa2e53 Dashboard: Various UI tweaks in project pages (#7905)
<!--

## 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 improving the layout across various pages in the dashboard application. It includes adjustments to button styles, layout properties, and content formatting for better user experience.

### Detailed summary
- Updated button styles for consistency (size and variant).
- Adjusted layout properties for various components (e.g., `max-w-7xl`, padding).
- Enhanced descriptions with line breaks for clarity.
- Modified component structures for better alignment and spacing.
- Removed unnecessary links from `webhooks` and `contracts` sections.
- Improved the `ProjectPageHeader` and `ProjectPageFooter` components.
- Revised `LinkGroup` to utilize dynamic icon rendering.
- Enhanced `EmptyStateCard` and `TotalSponsoredCard` layouts.

> ✨ 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
  - Headers now accept rich content (React nodes) enabling responsive line breaks.

- Style
  - Standardized small "secondary" bordered pill buttons across many actions and dialogs.
  - Updated header typography, spacing, avatar sizing, and max-width constraints for a more prominent layout.
  - Icons adjusted for size/color; token cards now stack vertically; dialog widths constrained; footer container width tightened.

- Bug Fixes / Refactor
  - Replaced visual separators with CSS borders and simplified DOM structure.
  - Removed certain header doc links from Webhooks and Payments pages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-25 17:09:36 +00:00
bdcbe0e25b Add ai usage section to dashboard (#7902)
Co-authored-by: Cursor Agent <[email protected]>
2025-08-24 19:47:56 -07:00
Joaquim VergesandGitHub 30e217870d [Docs] Update API domains (#7903) 2025-08-24 19:18:24 -07:00
Jonas DanielsandGitHub 44fdfeef1a Rename "Payment Links" to "Payments" in UI text (#7900) 2025-08-22 21:18:07 -07:00
0xFirekeeper 4cda30a87a Clarify authentication flows in wallet API docs (#7899)
Updated the documentation to distinguish between two-step authentication for email, phone, passkey, and SIWE, and single-step flows for guest, custom, and social authentication. Added details and endpoint references for each flow to improve clarity for API users.

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates the documentation for the authentication process in the `wallets` page, clarifying the steps for different authentication methods and introducing a new section on social authentication.

### Detailed summary
- Clarified the two-step authentication process for email, phone, passkey, or SIWE.
- Added information on skipping the first step for guest or custom authentication.
- Updated the description for initiating authentication to specify SIWE.
- Introduced a new section on social authentication, detailing a single-step flow.

> ✨ 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**
  * Clarified API Authentication flows: two-step for email, phone, passkey, or SIWE; skip-first-step option for guest or custom auth.
  * Updated headings and examples to reflect the revised two-step flow (initiate to get a challenge, then complete).
  * Added a Social Authentication section describing a single-step OAuth flow via a dedicated endpoint, with links to provider details and code samples.
  * Reorganized content so Get Wallet Information follows the updated authentication flows for better readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-23 00:37:20 +00:00
MananTank 98fab93e8b [BLD-166] Dashboard: Show Manage Contract button if user has used dashboard (#7898)
<!--

## 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 constant `HAS_USED_DASHBOARD` to track user engagement with the dashboard. It updates several components to include the `isDashboardUser` prop, allowing for conditional rendering based on whether the user has previously accessed the dashboard.

### Detailed summary
- Added `HAS_USED_DASHBOARD` constant in `cookie.ts`.
- Updated `NFTPublicPageLayout` to accept `isDashboardUser` prop.
- Modified `SaveLastVisitedTeamPage` to set `HAS_USED_DASHBOARD` cookie.
- Integrated `isDashboardUser` in `NFTPublicPage` and `ERC20PublicPage`.
- Updated `ContractHeaderUI` to conditionally render elements based on `isDashboardUser`.
- Enhanced storybook stories to include `isDashboardUser` prop for testing.

> ✨ 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**
  * Dashboard users are now detected via a persistent flag so public ERC20 and NFT pages can tailor the header UI and surface “Manage Contract” controls when appropriate.
  * Stories updated to cover dashboard vs non-dashboard header states.

* **Bug Fixes**
  * More reliable dashboard-user detection ensures the “Manage Contract” controls display consistently on public contract pages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-22 21:27:48 +00:00
MananTank 6caba380b2 [MNY-115] Dashboard: Fix token creation flow not working for custom chains (#7896)
<!--

## 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 custom hook `useGetV5DashboardChain` and modifies existing components to utilize this hook for chain management, improving code clarity and reducing redundancy.

### Detailed summary
- Added `useGetV5DashboardChain` hook in `v5-adapter.ts`.
- Updated `LaunchNFT` component to use `useV5DashboardChain`.
- Refactored `CreateTokenAssetPageUI` to use `useV5DashboardChain`.
- Refactored `CreateNFTPage` to use `getChain` from `useGetV5DashboardChain`.
- Refactored `CreateTokenAssetPage` to use `getChain` from `useGetV5DashboardChain`.

> ✨ 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 chain selection across NFT creation, NFT launch, and token creation flows using a single, consistent resolver.
  - Modernized internals for better compatibility with the latest chain data.

- Bug Fixes
  - Improved reliability of chain selection during deployments and validations, reducing chances of selecting the wrong network.
  - More consistent behavior when switching chains in forms and launch steps.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-21 19:26:44 +00:00
EimanandGitHub 68a07ed106 Portal Feature: changes to ai/mcp page to add buttons for downloading (#7890) 2025-08-21 11:49:17 -07:00
Jonas DanielsandGitHub b075ff55a1 Remove "dedicated" from engine URLs (#7897) 2025-08-21 09:28:25 -07:00
Jonas DanielsandGitHub 2d12249719 Remove "dedicated" from Engine URLs (#7894) 2025-08-20 21:35:47 -07:00
Jonas DanielsandGitHub 301b835b60 Remove RecentPaymentsSection and reduce payment history page size (#7893) 2025-08-20 20:33:51 -07:00
Jonas DanielsandGitHub a02b55744b unified project layout (#7888) 2025-08-20 18:38:12 -07:00
gregandGitHub 8b6deadc35 [Dashboard] Feature: Adds paired address for expedited token route finding (#7892) 2025-08-20 15:56:08 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
6d635dc266 Version Packages (#7891)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-20 10:24:39 -07:00
gregandGitHub 1083316ef6 [SDK] Feature: prepareCreateToken returns prepared transaction (#7872) 2025-08-20 10:06:41 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2c1ec47a04 Version Packages (#7889)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-20 03:50:57 -07:00
e01af9db71 fix: #7886 (#7887)
Signed-off-by: leo.shi <[email protected]>
Signed-off-by: Jonas Daniels <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2025-08-20 03:41:16 -07:00
Joaquim VergesandGitHub fd7e10d3de [Dashboard] Fix date handling in analytics components (#7885) 2025-08-19 17:59:55 -07:00
Joaquim VergesandGitHub 3126d87740 [Dashboard] improve wallet stats (#7880) 2025-08-19 15:51:01 -07:00
nischitpra b9e63ff0a7 add webhook id to test webhook (#7884)
<!-- start pr-codex -->

## PR-Codex overview
This PR introduces a new optional property `webhook_id` to the `TestWebhookPayload` interface and updates the call to `testWebhook` to include this new property.

### Detailed summary
- Added an optional property `webhook_id` to the `TestWebhookPayload` interface in `webhooks.ts`.
- Updated the `testWebhook` function call in `useTestWebhook.ts` to include `webhook_id` when invoking the function.

> ✨ 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**
  * Test Webhook requests now include the specific webhook ID when available, ensuring the test targets the correct webhook and improving reliability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-19 22:35:05 +00:00
Jonas DanielsandGitHub 77053049a5 Always show Chain Infrastructure in sidebar regardless of subscriptions (#7883) 2025-08-19 09:51:09 -07:00
Joaquim VergesGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
557d42d4f4 Version Packages (#7871)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-18 15:06:25 -07:00
saminaGitHubgraphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
0a662c1f0c Update Payments FAQ (#7845)
Signed-off-by: samina <[email protected]>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-08-18 15:04:21 -07:00
gregandGitHub f78b0a28da Feature: predictAddress token function (#7870) 2025-08-18 15:04:02 -07:00
MananTank e0ab3d5f27 Dashboard: Fix NFT Collection creation error reported twice (#7868)
<!--

## 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 `CreateNFTPage` component in `create-nft-page.tsx` to streamline contract deployment processes and improve error handling by removing redundant code and optimizing the reporting of contract deployment.

### Detailed summary
- Removed the import of `reportAssetCreationFailed`.
- Simplified the contract deployment logic for `erc721` and `erc1155`.
- Moved the `reportContractDeployed` call directly after contract creation.
- Eliminated redundant error handling in several transaction functions.
- Updated calls to `sendAndConfirmTransaction` to remove try-catch blocks.

> ✨ 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
  - None
- Refactor
  - Streamlined NFT creation flows for a smoother experience: deterministic ERC721/ERC1155 deployment, simplified lazy minting, claim condition setup, and admin assignment.
  - Contracts are automatically linked to the project in the background after deployment.
- Chores
  - Improved post-deployment tracking by recording deployed contract details (address, chain, name, type, publisher) for better observability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-08-18 19:39:25 +00:00
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
1454 changed files with 51465 additions and 22501 deletions
+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=""
+30
View File
@@ -95,6 +95,36 @@ module.exports = {
'Import "posthog-js" directly only within the analytics helpers ("src/@/analytics/*"). Use the exported helpers from "@/analytics/track" elsewhere.',
name: "posthog-js",
},
{
importNames: ["useSendTransaction"],
message:
'Use `import { useSendAndConfirmTx } from "@/hooks/useSendTx";` instead',
name: "thirdweb/react",
},
{
importNames: ["useSendAndConfirmTransaction"],
message:
'Use `import { useSendAndConfirmTx } from "@/hooks/useSendTx";` instead',
name: "thirdweb/react",
},
{
importNames: ["sendTransaction"],
message:
'Use `import { useSendAndConfirmTx } from "@/hooks/useSendTx";` instead if used in react component',
name: "thirdweb",
},
{
importNames: ["sendAndConfirmTransaction"],
message:
'Use `import { useSendAndConfirmTx } from "@/hooks/useSendTx";` instead if used in react component',
name: "thirdweb",
},
],
patterns: [
{
group: ["**/../@/**"],
message: "Use absolute imports instead. Example: '@/foo/bar..'",
},
],
},
],
+6 -9
View File
@@ -1,14 +1,13 @@
import type { Preview } from "@storybook/nextjs";
import "../src/global.css";
import "@workspace/ui/global.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Button } from "@workspace/ui/components/button";
import { MoonIcon, SunIcon } from "lucide-react";
import { ThemeProvider, useTheme } from "next-themes";
import { Inter as interFont } from "next/font/google";
// biome-ignore lint/style/useImportType: <explanation>
import React from "react";
import { useEffect } from "react";
import { ThemeProvider, useTheme } from "next-themes";
// biome-ignore lint/style/useImportType: ok
import React, { useEffect } from "react";
import { Toaster } from "sonner";
import { Button } from "../src/@/components/ui/button";
const queryClient = new QueryClient();
@@ -69,9 +68,7 @@ const preview: Preview = {
export default preview;
function StoryLayout(props: {
children: React.ReactNode;
}) {
function StoryLayout(props: { children: React.ReactNode }) {
const { setTheme, theme } = useTheme();
useEffect(() => {
+2 -2
View File
@@ -21,8 +21,8 @@ module.exports = [
"/storage",
// -- end scale category
// -- nebula
"/nebula",
// -- ai
"/ai",
// -- contracts
"/contracts",
"/contracts/modular-contracts",
+9 -1
View File
@@ -10,8 +10,16 @@
"ignoreDependencies": [
"@thirdweb-dev/service-utils",
"@thirdweb-dev/vault-sdk",
"thirdweb",
"@types/color",
"fast-xml-parser"
"fast-xml-parser",
"@workspace/ui",
"tailwindcss-animate",
"@radix-ui/react-tooltip",
"shiki",
"react-children-utilities",
"react-markdown",
"remark-gfm"
],
"next": true,
"project": ["src/**"]
+3 -3
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,6 +115,7 @@ const SENTRY_OPTIONS: SentryBuildOptions = {
const FRAMER_ADDITIONAL_LANGUAGES = ["es"];
const baseNextConfig: NextConfig = {
transpilePackages: ["@workspace/ui"],
eslint: {
ignoreDuringBuilds: true,
},
@@ -196,7 +197,6 @@ const baseNextConfig: NextConfig = {
]),
];
},
serverExternalPackages: ["pino-pretty"],
};
function getConfig(): NextConfig {
+3 -6
View File
@@ -19,7 +19,6 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tooltip": "1.2.7",
"@scalar/api-reference-react": "0.7.25",
"@sentry/nextjs": "9.34.0",
"@shazow/whatsabi": "0.22.2",
"@tanstack/react-query": "5.81.5",
@@ -28,6 +27,7 @@
"@thirdweb-dev/vault-sdk": "workspace:*",
"@vercel/functions": "2.2.2",
"@vercel/og": "^0.6.8",
"@workspace/ui": "workspace:*",
"abitype": "1.0.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -43,11 +43,9 @@
"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",
"react": "19.1.0",
"react-children-utilities": "^2.10.0",
@@ -57,13 +55,12 @@
"react-error-boundary": "6.0.0",
"react-hook-form": "7.55.0",
"react-markdown": "10.1.0",
"react-qrcode-logo": "^3.0.0",
"react-table": "^7.8.0",
"recharts": "2.15.3",
"remark-gfm": "4.0.1",
"responsive-rsc": "0.0.7",
"server-only": "^0.0.1",
"shiki": "1.27.0",
"shiki": "3.12.0",
"sonner": "2.0.6",
"spdx-correct": "^3.2.0",
"stripe": "17.7.0",
@@ -130,4 +127,4 @@
"update-checkly": "npx checkly deploy"
},
"version": "3.0.0"
}
}
-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";
+6
View File
@@ -460,6 +460,12 @@ async function redirects() {
permanent: false,
source: "/universal-bridge",
},
// redirect /nebula to /ai
{
destination: "/ai",
permanent: false,
source: "/nebula",
},
...legacyDashboardToTeamRedirects,
...projectPageRedirects,
...teamPageRedirects,
@@ -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();
@@ -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 }) {
@@ -1,57 +0,0 @@
import "server-only";
import { unstable_cache } from "next/cache";
import { PostHog } from "posthog-node";
let _posthogClient: PostHog | null = null;
function getPostHogServer(): PostHog | null {
if (!_posthogClient && process.env.NEXT_PUBLIC_POSTHOG_KEY) {
_posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
host: "https://us.i.posthog.com",
});
}
return _posthogClient;
}
/**
* Check if a feature flag is enabled for a specific user
* @param flagKey - The feature flag key
* @param userEmail - The user's email address for filtering
*/
export const isFeatureFlagEnabled = unstable_cache(
async (params: {
flagKey: string;
accountId: string;
email: string | undefined;
}): Promise<boolean> => {
const posthogClient = getPostHogServer();
if (!posthogClient) {
console.warn("Posthog client not set");
return true;
}
const { flagKey, accountId, email } = params;
try {
if (posthogClient && accountId) {
const isEnabled = await posthogClient.isFeatureEnabled(
flagKey,
accountId,
{
personProperties: email ? { email } : undefined,
},
);
if (isEnabled !== undefined) {
return isEnabled;
}
}
} catch (error) {
console.error(`Error checking feature flag ${flagKey}:`, error);
}
return false;
},
["is-feature-flag-enabled"],
{
revalidate: 3600, // 1 hour
},
);
+142 -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;
}
),
) {
@@ -428,3 +422,128 @@ export function reportUpsellClicked(properties: UpsellParams) {
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 { isAccountOnboardingComplete } from "@/utils/account-onboarding";
import { loginRedirect } from "@/utils/redirects";
import { isAccountOnboardingComplete } from "../../../login/onboarding/isOnboardingRequired";
/**
* 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}`);
}
}
@@ -58,6 +58,7 @@ interface WebhookSingleResponse {
}
interface TestWebhookPayload {
webhook_id?: string;
webhook_url: string;
type?: "event" | "transaction";
}
@@ -1,7 +1,7 @@
import {
getProjectContracts,
type ProjectContract,
} from "@/api/getProjectContracts";
} from "@/api/project/getProjectContracts";
import { fetchChainWithLocalOverrides } from "@/utils/fetchChainWithLocalOverrides";
export async function getSortedDeployedContracts(params: {
@@ -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;
@@ -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 };
@@ -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 =
| {
@@ -200,7 +200,11 @@ export async function createPaymentLink(props: {
throw new Error(text);
}
return;
const response = (await res.json()) as {
data: PaymentLink;
};
return response.data;
}
export async function deletePaymentLink(props: {
@@ -0,0 +1,35 @@
import { NEXT_PUBLIC_DASHBOARD_CLIENT_ID } from "@/constants/public-envs";
import { UB_BASE_URL } from "./constants";
import type { TokenMetadata } from "./types";
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");
url.searchParams.append("includePrices", "false");
const res = await fetch(url.toString(), {
headers: {
"Content-Type": "application/json",
"x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID,
} as Record<string, string>,
method: "GET",
});
if (!res.ok) {
const text = await res.text();
throw new Error(text);
}
const json = await res.json();
return json.data as Array<TokenMetadata>;
}
@@ -1,48 +1,8 @@
"use server";
import type { ProjectResponse } from "@thirdweb-dev/service-utils";
import { getAuthToken } from "@/api/auth-token";
import { DASHBOARD_THIRDWEB_SECRET_KEY } from "@/constants/server-envs";
import { UB_BASE_URL } from "./constants";
export type TokenMetadata = {
name: string;
symbol: string;
address: string;
decimals: number;
chainId: number;
iconUri?: string;
};
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(), {
headers: {
"Content-Type": "application/json",
"x-secret-key": DASHBOARD_THIRDWEB_SECRET_KEY,
} as Record<string, string>,
method: "GET",
});
if (!res.ok) {
const text = await res.text();
throw new Error(text);
}
const json = await res.json();
return json.data as Array<TokenMetadata>;
}
import type { TokenMetadata } from "./types";
export async function addUniversalBridgeTokenRoute(props: {
chainId: number;
@@ -0,0 +1,8 @@
export type TokenMetadata = {
name: string;
symbol: string;
address: string;
decimals: number;
chainId: number;
iconUri?: string;
};
-362
View File
@@ -1,362 +0,0 @@
"use server";
import { getAuthToken } from "@/api/auth-token";
import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs";
export interface WebhookConfig {
id: string;
teamId: string;
projectId: string;
destinationUrl: string;
description: string;
pausedAt: string | null;
webhookSecret: string;
createdAt: string;
updatedAt: string;
deletedAt: string | null;
topics: {
id: string;
serviceName: string;
description: string;
createdAt: string;
updatedAt: string;
deletedAt: string | null;
filters: object | null;
}[];
}
type WebhookConfigsResponse =
| {
data: WebhookConfig[];
status: "success";
}
| {
body: string;
reason: string;
status: "error";
};
interface CreateWebhookConfigRequest {
topicIdsWithFilters: { id: string; filters: object | null }[];
destinationUrl: string;
description: string;
isPaused?: boolean;
}
type CreateWebhookConfigResponse =
| {
data: WebhookConfig;
status: "success";
}
| {
body: string;
reason: string;
status: "error";
};
export interface Topic {
id: string;
serviceName: string;
description: string;
createdAt: string;
updatedAt: string;
deletedAt: string | null;
}
type TopicsResponse =
| {
data: Topic[];
status: "success";
}
| {
body: string;
reason: string;
status: "error";
};
interface UpdateWebhookConfigRequest {
destinationUrl?: string;
topicIdsWithFilters?: { id: string; filters: object | null }[];
description?: string;
isPaused?: boolean;
}
type UpdateWebhookConfigResponse =
| {
data: WebhookConfig;
status: "success";
}
| {
body: string;
reason: string;
status: "error";
};
type DeleteWebhookConfigResponse =
| {
data: WebhookConfig;
status: "success";
}
| {
body: string;
reason: string;
status: "error";
};
export async function getWebhookConfigs(props: {
teamIdOrSlug: string;
projectIdOrSlug: string;
}): Promise<WebhookConfigsResponse> {
const authToken = await getAuthToken();
if (!authToken) {
return {
body: "Authentication required",
reason: "no_auth_token",
status: "error",
};
}
const response = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${props.teamIdOrSlug}/projects/${props.projectIdOrSlug}/webhook-configs`,
{
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
method: "GET",
},
);
if (!response.ok) {
const body = await response.text();
return {
body,
reason: "unknown",
status: "error",
};
}
const result = await response.json();
return {
data: result.data,
status: "success",
};
}
export async function createWebhookConfig(props: {
teamIdOrSlug: string;
projectIdOrSlug: string;
config: CreateWebhookConfigRequest;
}): Promise<CreateWebhookConfigResponse> {
const authToken = await getAuthToken();
if (!authToken) {
return {
body: "Authentication required",
reason: "no_auth_token",
status: "error",
};
}
const response = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${props.teamIdOrSlug}/projects/${props.projectIdOrSlug}/webhook-configs`,
{
body: JSON.stringify(props.config),
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
method: "POST",
},
);
if (!response.ok) {
const body = await response.text();
return {
body,
reason: "unknown",
status: "error",
};
}
const result = await response.json();
return {
data: result.data,
status: "success",
};
}
export async function getAvailableTopics(): Promise<TopicsResponse> {
const authToken = await getAuthToken();
if (!authToken) {
return {
body: "Authentication required",
reason: "no_auth_token",
status: "error",
};
}
const response = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/webhook-topics`,
{
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
method: "GET",
},
);
if (!response.ok) {
const body = await response.text();
return {
body,
reason: "unknown",
status: "error",
};
}
const result = await response.json();
return {
data: result.data,
status: "success",
};
}
export async function updateWebhookConfig(props: {
teamIdOrSlug: string;
projectIdOrSlug: string;
webhookConfigId: string;
config: UpdateWebhookConfigRequest;
}): Promise<UpdateWebhookConfigResponse> {
const authToken = await getAuthToken();
if (!authToken) {
return {
body: "Authentication required",
reason: "no_auth_token",
status: "error",
};
}
const response = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${props.teamIdOrSlug}/projects/${props.projectIdOrSlug}/webhook-configs/${props.webhookConfigId}`,
{
body: JSON.stringify(props.config),
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
method: "PATCH",
},
);
if (!response.ok) {
const body = await response.text();
return {
body,
reason: "unknown",
status: "error",
};
}
const result = await response.json();
return {
data: result.data,
status: "success",
};
}
export async function deleteWebhookConfig(props: {
teamIdOrSlug: string;
projectIdOrSlug: string;
webhookConfigId: string;
}): Promise<DeleteWebhookConfigResponse> {
const authToken = await getAuthToken();
if (!authToken) {
return {
body: "Authentication required",
reason: "no_auth_token",
status: "error",
};
}
const response = await fetch(
`${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/teams/${props.teamIdOrSlug}/projects/${props.projectIdOrSlug}/webhook-configs/${props.webhookConfigId}`,
{
headers: {
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
method: "DELETE",
},
);
if (!response.ok) {
const body = await response.text();
return {
body,
reason: "unknown",
status: "error",
};
}
const result = await response.json();
return {
data: result.data,
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();
}
@@ -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,9 @@ 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();
todayDate.setDate(todayDate.getDate() + 1); // Move to next day
todayDate.setHours(0, 0, 0, 0); // Set to start of next day (00:00)
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 gap-3 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,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 { Spinner } from "@/components/ui/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;
@@ -10,7 +10,7 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { cn } from "../../lib/utils";
import { DynamicHeight } from "../ui/DynamicHeight";
@@ -3,7 +3,7 @@ import { DownloadIcon } from "lucide-react";
import Papa from "papaparse";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { cn } from "../../lib/utils";
export function ExportToCSVButton(props: {
@@ -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";
+1 -85
View File
@@ -1,87 +1,3 @@
/* eslint-disable @next/next/no-img-element */
"use client";
import { useRef, useState } from "react";
import { cn } from "@/lib/utils";
import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect";
type imgElementProps = React.DetailedHTMLProps<
React.ImgHTMLAttributes<HTMLImageElement>,
HTMLImageElement
> & {
skeleton?: React.ReactNode;
fallback?: React.ReactNode;
src: string | undefined;
containerClassName?: string;
};
export function Img(props: imgElementProps) {
const [_status, setStatus] = useState<"pending" | "fallback" | "loaded">(
"pending",
);
const status =
props.src === undefined
? "pending"
: props.src === ""
? "fallback"
: _status;
const { className, fallback, skeleton, containerClassName, ...restProps } =
props;
const defaultSkeleton = <div className="animate-pulse bg-accent" />;
const defaultFallback = <div className="bg-accent" />;
const imgRef = useRef<HTMLImageElement>(null);
useIsomorphicLayoutEffect(() => {
const imgEl = imgRef.current;
if (!imgEl) {
return;
}
if (imgEl.complete) {
setStatus("loaded");
} else {
function handleLoad() {
setStatus("loaded");
}
imgEl.addEventListener("load", handleLoad);
return () => {
imgEl.removeEventListener("load", handleLoad);
};
}
}, []);
return (
<div className={cn("relative shrink-0", containerClassName)}>
<img
{...restProps}
// avoid setting empty src string to prevent request to the entire page
alt={restProps.alt || ""}
className={cn(
"fade-in-0 object-cover transition-opacity duration-300",
className,
)}
decoding="async"
onError={() => {
setStatus("fallback");
}}
ref={imgRef}
src={restProps.src || undefined}
style={{
opacity: status === "loaded" ? 1 : 0,
...restProps.style,
}}
/>
{status !== "loaded" && (
<div
className={cn(
"fade-in-0 absolute inset-0 overflow-hidden transition-opacity duration-300 [&>*]:h-full [&>*]:w-full",
className,
)}
style={restProps.style}
>
{status === "pending" && (skeleton || defaultSkeleton)}
{status === "fallback" && (fallback || defaultFallback)}
</div>
)}
</div>
);
}
export { Img } from "@workspace/ui/components/img";
@@ -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(() => {
@@ -1,6 +1,6 @@
import type React from "react";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { cn } from "@/lib/utils";
export function RouteDiscoveryCard(
@@ -1,6 +1,6 @@
import type React from "react";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { cn } from "@/lib/utils";
export function SettingsCard(
@@ -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>
@@ -19,7 +19,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { Separator } from "@/components/ui/separator";
import {
Table,
@@ -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";
@@ -5,16 +5,16 @@ import {
type ThirdwebClient,
} from "thirdweb";
import { shortenAddress } from "thirdweb/utils";
import type { TokenMetadata } from "@/api/universal-bridge/tokens";
import type { TokenMetadata } from "@/api/universal-bridge/types";
import { Img } from "@/components/blocks/Img";
import { SelectWithSearch } from "@/components/blocks/select-with-search";
import { Badge } from "@/components/ui/badge";
import { Spinner } from "@/components/ui/Spinner";
import { fallbackChainIcon } from "@/constants/chain";
import { useAllChainsData } from "@/hooks/chains/allChains";
import { useTokensData } from "@/hooks/tokens";
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 };
@@ -204,7 +204,7 @@ export function TokenSelector(props: {
searchPlaceholder="Search by name or symbol"
showCheck={props.showCheck}
side={props.side}
value={selectedValue}
value={tokensQuery.isPending ? undefined : selectedValue}
/>
);
}
@@ -95,7 +95,6 @@ export const CodeSegment: React.FC<CodeSegmentProps> = ({
{!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) => ({
@@ -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,6 +1,6 @@
import { useMemo } from "react";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { ScrollShadow } from "@/components/ui/ScrollShadow";
export function UnexpectedValueErrorMessage(props: {
value: unknown;
@@ -91,7 +91,7 @@ export function FullWidthSidebarLayout(props: {
<main className="flex min-w-0 grow flex-col max-sm:w-full">
{children}
</main>
<AppFooter containerClassName="max-w-7xl" />
<AppFooter />
</div>
</div>
);
@@ -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>
);
}
@@ -1,225 +1 @@
import { onlyText } from "react-children-utilities";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { CodeClient } from "@/components/ui/code/code.client";
import { PlainTextCodeBlock } from "@/components/ui/code/plaintext-code";
import { InlineCode } from "@/components/ui/inline-code";
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { UnderlineLink } from "@/components/ui/UnderlineLink";
import { cn } from "@/lib/utils";
export const MarkdownRenderer: React.FC<{
markdownText: string;
className?: string;
code?: {
disableCodeHighlight?: boolean;
ignoreFormattingErrors?: boolean;
className?: string;
};
inlineCode?: {
className?: string;
};
p?: {
className?: string;
};
li?: {
className?: string;
};
skipHtml?: boolean;
}> = (markdownProps) => {
const { markdownText, className, code } = markdownProps;
const commonHeadingClassName = "mb-2 leading-5 font-semibold tracking-tight";
return (
<div className={className}>
<ReactMarkdown
components={{
a: (props) => (
<UnderlineLink
href={props.href ?? "#"}
rel="noopener noreferrer"
target="_blank"
{...cleanedProps(props)}
className="mt-4"
/>
),
code: ({ ...props }) => {
const codeStr = onlyText(props.children);
if (props?.className || codeStr.length > 100) {
if (code?.disableCodeHighlight || !props.className) {
return (
<div className="my-4">
{/* @ts-expect-error - TODO: fix this */}
<PlainTextCodeBlock
{...cleanedProps(props)}
className={markdownProps.code?.className}
code={onlyText(props.children).trim()}
/>
</div>
);
}
const language = props.className.replace("language-", "");
return (
<div className="my-4">
<CodeClient
// @ts-expect-error - TODO: fix this
lang={language}
{...cleanedProps(props)}
className={markdownProps.code?.className}
code={onlyText(props.children).trim()}
ignoreFormattingErrors={code?.ignoreFormattingErrors}
/>
</div>
);
}
return (
<InlineCode
className={markdownProps.inlineCode?.className}
code={onlyText(props.children).trim()}
/>
);
},
h1: (props) => (
<h2
className={cn(
commonHeadingClassName,
"mb-3 border-dashed border-b pb-2 text-xl md:text-2xl",
)}
{...cleanedProps(props)}
/>
),
h2: (props) => (
<h3
{...cleanedProps(props)}
className={cn(
commonHeadingClassName,
"mt-8 mb-3 border-dashed border-b pb-2 text-lg md:text-xl",
)}
/>
),
h3: (props) => (
<h4
{...cleanedProps(props)}
className={cn(
commonHeadingClassName,
"mt-4 text-base md:text-lg",
)}
/>
),
h4: (props) => (
<h5
{...cleanedProps(props)}
className={cn(commonHeadingClassName, "mt-4 text-lg")}
/>
),
h5: (props) => (
<h6
{...cleanedProps(props)}
className={cn(commonHeadingClassName, "mt-4 text-lg")}
/>
),
h6: (props) => (
<p
{...cleanedProps(props)}
className={cn(commonHeadingClassName, "mt-4 text-lg")}
/>
),
hr: (props) => (
<hr {...cleanedProps(props)} className="my-5 bg-border" />
),
li: ({ children: c, ...props }) => (
<li
className={cn(
"text-muted-foreground leading-relaxed [&>p]:m-0",
markdownProps.li?.className,
)}
{...cleanedProps(props)}
>
{c}
</li>
),
ol: (props) => (
<ol
className="mb-4 list-outside list-decimal pl-4 space-y-2 [&>li]:first:mt-2"
{...cleanedProps(props)}
/>
),
p: (props) => (
<p
className={cn(
"mb-3 text-muted-foreground leading-7",
markdownProps.p?.className,
)}
{...cleanedProps(props)}
/>
),
strong(props) {
return <strong className="font-medium" {...cleanedProps(props)} />;
},
table: (props) => (
<div className="mb-6">
<TableContainer>
<Table {...cleanedProps(props)} />
</TableContainer>
</div>
),
tbody: (props) => <TableBody {...cleanedProps(props)} />,
td: (props) => (
<TableCell {...cleanedProps(props)} className="text-left" />
),
th: ({ children: c, ...props }) => (
<TableHead
{...cleanedProps(props)}
className="text-left text-muted-foreground"
>
{c}
</TableHead>
),
thead: (props) => <TableHeader {...cleanedProps(props)} />,
tr: (props) => <TableRow {...cleanedProps(props)} />,
ul: (props) => {
return (
<ul
className="mb-4 list-outside list-disc pl-4 space-y-2 [&>li]:first:mt-2"
{...cleanedProps(props)}
/>
);
},
}}
remarkPlugins={[remarkGfm]}
skipHtml={markdownProps.skipHtml}
>
{markdownText}
</ReactMarkdown>
</div>
);
};
function cleanedProps<T extends object & { node?: unknown }>(
props: T,
): Omit<T, "node"> {
// biome-ignore lint/correctness/noUnusedVariables: EXPECTED
const { node, ...rest } = props;
return rest;
}
export { MarkdownRenderer } from "@workspace/ui/components/markdown-renderer";
@@ -10,7 +10,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { ScrollShadow } from "@/components/ui/ScrollShadow";
import { Separator } from "@/components/ui/separator";
import { useShowMore } from "@/hooks/useShowMore";
import { cn } from "@/lib/utils";
@@ -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,
@@ -7,8 +7,8 @@ import {
RefreshCwIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { DynamicHeight } from "../../ui/DynamicHeight";
import { Spinner } from "../../ui/Spinner/Spinner";
import { DynamicHeight } from "@/components/ui/DynamicHeight";
import { Spinner } from "@/components/ui/Spinner";
export type MultiStepState<T extends string> = {
id: T;
@@ -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
@@ -0,0 +1,119 @@
"use client";
import { Button } from "@workspace/ui/components/button";
import {
BookTextIcon,
BoxIcon,
ChevronDownIcon,
CodeIcon,
WebhookIcon,
} from "lucide-react";
import Link from "next/link";
import { useMemo } from "react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
type LinkType = "api" | "docs" | "playground" | "webhooks";
const linkTypeToLabel: Record<LinkType, string> = {
api: "API Reference",
docs: "Documentation",
playground: "Playground",
webhooks: "Webhooks",
};
const linkTypeToOrder: Record<LinkType, number> = {
docs: 0,
playground: 1,
api: 3,
webhooks: 4,
};
const linkTypeToIcon: Record<LinkType, React.FC<{ className?: string }>> = {
api: CodeIcon,
docs: BookTextIcon,
playground: BoxIcon,
webhooks: WebhookIcon,
};
function orderLinks(links: ActionLink[]) {
return links.slice().sort((a, b) => {
const aIndex = linkTypeToOrder[a.type];
const bIndex = linkTypeToOrder[b.type];
return aIndex - bIndex;
});
}
export type ActionLink = {
type: LinkType;
href: string;
};
export function LinkGroup(props: { links: ActionLink[] }) {
const orderedLinks = useMemo(() => orderLinks(props.links), [props.links]);
if (orderedLinks.length === 1 && orderedLinks[0]) {
const link = orderedLinks[0];
const Icon = linkTypeToIcon[link.type];
return (
<Link
href={link.href}
target={link.href.startsWith("http") ? "_blank" : undefined}
>
<Button
variant="outline"
size="sm"
className="rounded-full border gap-2 bg-card"
>
<Icon className="size-3.5 text-muted-foreground" />
{linkTypeToLabel[link.type]}
</Button>
</Link>
);
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="rounded-full border gap-2 bg-card [&[data-state=open]>svg]:rotate-180"
>
Resources
<ChevronDownIcon className="size-4 transition-transform duration-200 text-muted-foreground" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="gap-1 flex flex-col w-48 rounded-xl"
sideOffset={10}
>
{orderedLinks.map((link) => {
const isExternal = link.href.startsWith("http");
const Icon = linkTypeToIcon[link.type];
return (
<DropdownMenuItem
key={link.type}
asChild
className="flex flex-row items-center gap-2 cursor-pointer py-1.5"
>
<Link
href={link.href}
target={isExternal ? "_blank" : undefined}
rel={isExternal ? "noopener noreferrer" : undefined}
>
<Icon className="size-4 text-muted-foreground" />
{linkTypeToLabel[link.type]}
</Link>
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
);
}
@@ -0,0 +1,14 @@
import {
type FooterCardProps,
FooterLinksSection,
} from "../../../../app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/footer/FooterLinksSection";
export type ProjectPageFooterProps = FooterCardProps;
export function ProjectPageFooter(props: ProjectPageFooterProps) {
return (
<footer className="container max-w-7xl">
<FooterLinksSection {...props} />
</footer>
);
}
@@ -0,0 +1,155 @@
import { Button } from "@workspace/ui/components/button";
import { ArrowUpRightIcon, Settings2Icon } from "lucide-react";
import Link from "next/link";
import type { ThirdwebClient } from "thirdweb";
import { cn } from "@/lib/utils";
import { type ActionLink, LinkGroup } from "./header/link-group";
type Action =
| ({
label: string;
href: string;
} & (
| {
external: true;
icon?: never;
}
| {
icon?: React.ReactNode;
external?: false;
}
))
| {
component: React.ReactNode;
};
function Action(props: { action: Action; variant?: "default" | "secondary" }) {
const action = props.action;
return "component" in action ? (
action.component
) : (
<Button
asChild
className={cn(
"rounded-full",
props.variant === "secondary" && "border border-border",
)}
size="sm"
variant={props.variant}
>
<Link
href={action.href}
target={action.external ? "_blank" : undefined}
rel={action.external ? "noopener noreferrer" : undefined}
className="flex flex-row items-center gap-2"
>
{action.icon}
{action.label}
{action.external && <ArrowUpRightIcon className="size-4" />}
</Link>
</Button>
);
}
export type ProjectPageHeaderProps = {
client: ThirdwebClient;
title: string;
description?: React.ReactNode;
imageUrl?: string | null;
icon: React.FC<{ className?: string }>;
isProjectIcon?: boolean;
actions: {
primary: Action;
secondary?: Action;
} | null;
links?: ActionLink[];
settings?: {
href: string;
};
// TODO: add task card component
task?: never;
};
export function ProjectPageHeader(props: ProjectPageHeaderProps) {
return (
<header className="container max-w-7xl py-6 relative">
{/* top row */}
<div className="flex justify-between items-start mb-4">
{/* left - icon */}
<div className="flex">
{props.isProjectIcon ? (
<props.icon />
) : (
<div className="border rounded-full p-2.5 bg-card">
<props.icon className="size-5 text-muted-foreground" />
</div>
)}
</div>
{/* right - buttons */}
<div className="flex items-center gap-3">
<div className="flex items-center gap-3">
{props.links && props.links.length > 0 && (
<LinkGroup links={props.links} />
)}
{props.settings && (
<Link href={props.settings.href}>
<Button
variant="outline"
size="sm"
className="rounded-full gap-2 bg-card"
>
<Settings2Icon className="size-4 text-muted-foreground" />
Settings
</Button>
</Link>
)}
</div>
{/* hide on mobile */}
{props.actions && (
<div className="hidden lg:flex items-center gap-3">
{props.actions.secondary && (
<Action action={props.actions.secondary} variant="secondary" />
)}
{props.actions.primary && (
<Action action={props.actions.primary} />
)}
</div>
)}
</div>
</div>
<div className="space-y-4">
{/* mid row */}
<div className="space-y-1 max-w-3xl">
<h2 className="text-3xl font-semibold tracking-tight">
{props.title}
</h2>
{/* description */}
<p className="text-sm text-muted-foreground line-clamp-3 md:line-clamp-2">
{props.description}
</p>
</div>
{/* bottom row - hidden on desktop */}
{props.actions && (
<div className="flex items-center gap-3 lg:hidden">
{props.actions?.primary && (
<Action action={props.actions.primary} />
)}
{props.actions?.secondary && (
<Action action={props.actions.secondary} variant="secondary" />
)}
</div>
)}
</div>
</header>
);
}
@@ -0,0 +1,44 @@
import { cn } from "@/lib/utils";
import { type TabPathLink, TabPathLinks } from "../../ui/tabs";
import {
ProjectPageFooter,
type ProjectPageFooterProps,
} from "./project-page-footer";
import {
ProjectPageHeader,
type ProjectPageHeaderProps,
} from "./project-page-header";
type ProjectPageProps = {
header: ProjectPageHeaderProps;
footer?: ProjectPageFooterProps;
/**
* @deprecated only for legacy pages where we still need internal tabs for the moment, currently:
* - /webhooks
*/
tabs?: TabPathLink[];
};
export function ProjectPage(props: React.PropsWithChildren<ProjectPageProps>) {
return (
<div className="flex flex-col grow">
<div className={cn(!props.tabs && "border-b")}>
<ProjectPageHeader {...props.header} />
{props.tabs && (
<TabPathLinks
scrollableClassName="container max-w-7xl"
links={props.tabs}
/>
)}
</div>
<main className="container max-w-7xl pt-6">{props.children}</main>
<div className="h-20" />
{props.footer && (
<div className="border-t mt-auto">
<ProjectPageFooter {...props.footer} />
</div>
)}
</div>
);
}
@@ -10,7 +10,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { ScrollShadow } from "@/components/ui/ScrollShadow";
import { useShowMore } from "@/hooks/useShowMore";
import { cn } from "@/lib/utils";
@@ -1,6 +1,6 @@
"use client";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { cn } from "@/lib/utils";
export function GenericLoadingPage({ className }: { className?: string }) {
@@ -3,7 +3,7 @@
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";
@@ -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,6 +23,7 @@ export function WalletAddress(props: {
className?: string;
iconClassName?: string;
client: ThirdwebClient;
fallbackIcon?: React.ReactNode;
}) {
// default back to zero address if no address provided
const address = useMemo(() => props.address || ZERO_ADDRESS, [props.address]);
@@ -47,7 +48,7 @@ export function WalletAddress(props: {
return (
<ToolTipLabel hoverable label={address}>
<span className="flex items-center gap-2 underline-offset-4 hover:underline">
<div className="flex size-6 items-center justify-center rounded-full border bg-background">
<div className="flex size-5 items-center justify-center rounded-full border bg-background">
<XIcon className="size-4 text-muted-foreground" />
</div>
Invalid Address
@@ -59,9 +60,16 @@ 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-5 text-muted-foreground/70", props.iconClassName)}
/>
<span
className={cn("cursor-pointer font-mono text-sm", props.className)}
>
{shortenedAddress}
</span>
</div>
);
}
@@ -82,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">
@@ -173,6 +182,7 @@ function WalletAvatar(props: {
profiles: SocialProfile[];
thirdwebClient: ThirdwebClient;
iconClassName?: string;
fallbackIcon?: React.ReactNode;
}) {
const avatar = useMemo(() => {
return props.profiles.find(
@@ -192,18 +202,27 @@ 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}
fallback={
<Blobbie
address={props.address}
className={props.iconClassName}
size={20}
/>
}
/>
) : props.fallbackIcon ? (
props.fallbackIcon
) : (
<Blobbie
address={props.address}
className={props.iconClassName}
size={24}
size={20}
/>
)}
</div>
@@ -4,7 +4,7 @@ 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";
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";
@@ -2,7 +2,7 @@
import { useCallback, useState } from "react";
import type { ThirdwebClient } from "thirdweb";
import { useActiveWalletConnectionStatus } from "thirdweb/react";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { Button } from "@/components/ui/button";
import { ThirdwebMiniLogo } from "../../../app/(app)/components/ThirdwebMiniLogo";
import { ChatBar } from "./ChatBar";
@@ -6,7 +6,7 @@ import {
} from "lucide-react";
import { useEffect, useRef, useState } from "react";
import type { ThirdwebClient } from "thirdweb";
import type { Team } from "@/api/team";
import type { Team } from "@/api/team/get-team";
import { MarkdownRenderer } from "@/components/blocks/markdown-renderer";
import { DynamicHeight } from "@/components/ui/DynamicHeight";
import {
@@ -15,7 +15,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { ScrollShadow } from "@/components/ui/ScrollShadow";
import { cn } from "@/lib/utils";
import { ThirdwebMiniLogo } from "../../../app/(app)/components/ThirdwebMiniLogo";
import { SupportTicketForm } from "../../../app/(app)/team/[team_slug]/(team)/~/support/_components/SupportTicketForm";
@@ -413,15 +413,15 @@ function StyledMarkdownRenderer(props: {
}) {
return (
<MarkdownRenderer
className="[&>*:first-child]:mt-0 [&>*:first-child]:border-none [&>*:first-child]:pb-0 [&>*:last-child]:mb-0"
className="text-sm text-foreground [&>*:first-child]:mt-0 [&>*:first-child]:border-none [&>*:first-child]:pb-0 [&>*:last-child]:mb-0 leading-relaxed"
code={{
className: "bg-card",
ignoreFormattingErrors: true,
}}
inlineCode={{ className: "border-none" }}
li={{ className: "text-foreground leading-relaxed" }}
markdownText={props.text}
p={{
className: props.type === "assistant" ? "" : "leading-normal",
className: "text-foreground leading-relaxed",
}}
skipHtml
/>
@@ -22,8 +22,8 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { ScrollShadow } from "@/components/ui/ScrollShadow";
import { Spinner } from "@/components/ui/Spinner";
import { ChainIconClient } from "@/icons/ChainIcon";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { fetchTopContracts, type TrendingContract } from "@/lib/search";
@@ -1,6 +1,5 @@
"use client";
import { useFavoriteChainIds } from "@app/(dashboard)/(chain)/components/client/star-button";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
@@ -20,6 +19,7 @@ import { LazyConfigureNetworkModal } from "@/components/misc/configure-networks/
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,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
import { ThirdwebProvider } from "thirdweb/react";
import type { ProjectContract } from "@/api/getProjectContracts";
import type { ProjectContract } from "@/api/project/getProjectContracts";
import { BadgeContainer, storybookThirdwebClient } from "@/storybook/utils";
import { ContractTableUI } from "./contract-table";
@@ -6,7 +6,7 @@ import Link from "next/link";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { toast } from "sonner";
import type { ThirdwebClient } from "thirdweb";
import type { ProjectContract } from "@/api/getProjectContracts";
import type { ProjectContract } from "@/api/project/getProjectContracts";
import { PaginationButtons } from "@/components/blocks/pagination-buttons";
import { NetworkSelectDropdown } from "@/components/contract-components/tables/NetworkSelectDropdown";
import { Badge } from "@/components/ui/badge";
@@ -17,7 +17,7 @@ import {
DropdownMenuContent,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { SkeletonContainer } from "@/components/ui/skeleton";
import {
Table,
@@ -300,6 +300,7 @@ const contractTypeToAssetTypeRecord: Record<string, string | undefined> = {
DropERC20: "Coin",
DropERC721: "NFT Collection",
DropERC1155: "NFT Collection",
ERC20Asset: "Coin",
};
const NetworkFilterCell = React.memo(function NetworkFilterCell({
@@ -14,11 +14,11 @@ import * as ERC1155Ext from "thirdweb/extensions/erc1155";
import * as ERC4337Ext from "thirdweb/extensions/erc4337";
import { useActiveAccount } from "thirdweb/react";
import { toFunctionSelector } from "thirdweb/utils";
import { getContractFunctionsFromAbi } from "@/api/contract/getContractFunctionsFromAbi";
import {
type CodeEnvironment,
CodeSegment,
} from "@/components/blocks/code/code-segment.client";
import { getContractFunctionsFromAbi } from "@/components/contract-components/getContractFunctionsFromAbi";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { TabButtons } from "@/components/ui/tabs";
@@ -743,7 +743,6 @@ export function CodeOverview(props: {
<div className="bg-background">
<TabButtons
tabs={tabList}
tabClassName="!text-sm"
tabContainerClassName="px-3 pt-2"
/>
</div>
@@ -1,19 +1,20 @@
import { moduleToBase64 } from "app/(app)/(dashboard)/published-contract/utils/module-base-64";
import { RocketIcon, ShieldCheckIcon } from "lucide-react";
import { unstable_cache } from "next/cache";
import Link from "next/link";
import { ClientOnly } from "@/components/blocks/client-only";
import { fetchPublishedContractVersion } from "@/components/contract-components/fetch-contracts-with-versions";
import { resolveAvatar } from "thirdweb/extensions/ens";
import { fetchPublishedContractVersion } from "@/api/contract/fetch-contracts-with-versions";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
import { serverThirdwebClient } from "@/constants/thirdweb-client.server";
import { resolveEns } from "@/lib/ens";
import { replaceDeployerAddress } from "@/lib/publisher-utils";
import { cn } from "@/lib/utils";
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
import { ContractPublisher } from "../../../../app/(app)/(dashboard)/explore/components/publisher";
import { ContractPublisher } from "./contract-publisher";
interface ContractCardProps {
type ContractCardProps = {
publisher: string;
contractId: string;
titleOverride?: string;
@@ -29,7 +30,7 @@ interface ContractCardProps {
moduleId: string;
version?: string;
}[];
}
};
function getContractUrl(
{
@@ -74,6 +75,72 @@ function getContractUrl(
return replaceDeployerAddress(pathName);
}
const cached_fetchPublishedContractVersion = unstable_cache(
async (publisher: string, contractId: string, version: string = "latest") => {
const result = await fetchPublishedContractVersion(
publisher,
contractId,
serverThirdwebClient,
version,
).catch(() => null);
if (!result) {
return null;
}
const publisherEnsAndAvatar = result.publisher
? await cached_resolvePublisherEnsAndAvatar(result.publisher)
: undefined;
// Note: Do not return BigInt - it can't be serialized and cached by unstable_cache and will throw an error
return {
name: result.name,
displayName: result.displayName,
description: result.description,
publisher: {
address: result.publisher,
ensName: publisherEnsAndAvatar?.ensName,
ensAvatar: publisherEnsAndAvatar?.ensAvatar,
},
version: result.version,
audit: result.audit,
};
},
["fetchPublishedContractVersion"],
{
revalidate: 3600, // 1 hour
},
);
const cached_resolvePublisherEnsAndAvatar = unstable_cache(
async (_addressOrEns: string) => {
const addressOrEns = replaceDeployerAddress(_addressOrEns);
const [ensNameInfo, ensAvatar] = await Promise.allSettled([
resolveEns(addressOrEns, serverThirdwebClient),
resolveAvatar({
client: serverThirdwebClient,
name: addressOrEns,
}),
]);
return {
ensName:
ensNameInfo.status === "fulfilled"
? ensNameInfo.value?.ensName
: undefined,
address:
ensNameInfo.status === "fulfilled"
? ensNameInfo.value?.address
: undefined,
ensAvatar: ensAvatar.status === "fulfilled" ? ensAvatar.value : undefined,
};
},
["resolvePublisherEnsAndAvatar"],
{
revalidate: 3600, // 1 hour
},
);
export async function ContractCard({
publisher,
contractId,
@@ -83,12 +150,11 @@ export async function ContractCard({
modules = [],
isBeta,
}: ContractCardProps) {
const publishedContractResult = await fetchPublishedContractVersion(
const publishedContractResult = await cached_fetchPublishedContractVersion(
publisher,
contractId,
serverThirdwebClient,
version,
).catch(() => null);
);
if (!publishedContractResult) {
return null;
@@ -186,13 +252,12 @@ export async function ContractCard({
!modules?.length && "mt-auto",
)}
>
{publishedContractResult.publisher && (
<ClientOnly ssr={<Skeleton className="size-5 rounded-full" />}>
<ContractPublisher
addressOrEns={publishedContractResult.publisher}
client={getClientThirdwebClient()}
/>
</ClientOnly>
{publishedContractResult.publisher.address && (
<ContractPublisher
address={publishedContractResult.publisher.address}
ensName={publishedContractResult.publisher.ensName || undefined}
ensAvatar={publishedContractResult.publisher.ensAvatar || undefined}
/>
)}
<div className="flex items-center justify-between">
@@ -0,0 +1,36 @@
"use client";
import Link from "next/link";
import { Blobbie } from "thirdweb/react";
import { Img } from "@/components/blocks/Img";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
import { resolveSchemeWithErrorHandler } from "@/utils/resolveSchemeWithErrorHandler";
import { shortenIfAddress } from "@/utils/usedapp-external";
export function ContractPublisher(props: {
ensName: string | undefined;
address: string;
ensAvatar: string | undefined;
}) {
const displayName = props.ensName || props.address;
return (
<Link
className="flex shrink-0 items-center gap-1.5 hover:underline"
href={`/${displayName}`}
target="_blank"
>
<Img
className="size-5 rounded-full object-cover"
src={
resolveSchemeWithErrorHandler({
client: getClientThirdwebClient(),
uri: props.ensAvatar,
}) || ""
}
fallback={<Blobbie address={props.address} />}
/>
<span className="text-xs"> {shortenIfAddress(displayName)}</span>
</Link>
);
}
@@ -1,5 +1,5 @@
import Link from "next/link";
import { fetchDeployMetadata } from "@/components/contract-components/fetchDeployMetadata";
import { fetchDeployMetadata } from "@/api/contract/fetchDeployMetadata";
import { ContractIdImage } from "@/components/contract-components/shared/contract-id-image";
import {
Table,
@@ -332,7 +332,6 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
<div className="flex flex-col h-full relative">
<TabButtons
tabContainerClassName="px-3 pt-2"
tabClassName="!text-sm"
tabs={[
...(viewFunctions.length > 0
? [
@@ -20,7 +20,7 @@ import {
toSerializableTransaction,
toWei,
} from "thirdweb";
import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react";
import { useActiveAccount } from "thirdweb/react";
import { parseAbiParams, stringify, toFunctionSelector } from "thirdweb/utils";
import { FormFieldSetup } from "@/components/blocks/FormFieldSetup";
import { SolidityInput } from "@/components/solidity-inputs";
@@ -30,11 +30,11 @@ import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { CodeClient } from "@/components/ui/code/code.client";
import { PlainTextCodeBlock } from "@/components/ui/code/plaintext-code";
import { InlineCode } from "@/components/ui/inline-code";
import { Input } from "@/components/ui/input";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Spinner } from "@/components/ui/Spinner";
import { Skeleton } from "@/components/ui/skeleton";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { useSendAndConfirmTx } from "@/hooks/useSendTx";
function formatResponseData(data: unknown): {
type: "json" | "text";
@@ -265,7 +265,7 @@ export const InteractiveAbiFunction: React.FC<InteractiveAbiFunctionProps> = (
data: mutationData,
error: mutationError,
isPending: mutationLoading,
} = useSendAndConfirmTransaction();
} = useSendAndConfirmTx();
const {
mutate: readFn,
@@ -414,14 +414,13 @@ export const InteractiveAbiFunction: React.FC<InteractiveAbiFunctionProps> = (
)}
{error ? (
<>
<h3 className="text-sm font-medium">Error</h3>
<InlineCode
className="relative w-full whitespace-pre-wrap rounded-md border border-border p-4 text-red-500"
// biome-ignore lint/suspicious/noExplicitAny: FIXME
code={formatError(error as any)}
<div>
<h3 className="text-sm font-medium mb-2">Error</h3>
<PlainTextCodeBlock
className="text-red-500 bg-background"
code={formatError(error)}
/>
</>
</div>
) : readLoading ? (
<Skeleton className="h-20 w-full rounded-lg" />
) : formattedResponseData ? (
@@ -1,14 +1,10 @@
"use client";
import { CircleAlertIcon, ExternalLinkIcon } from "lucide-react";
import { useId } from "react";
import type { ThirdwebClient } from "thirdweb";
import type { Project } from "@/api/projects";
import type { Team } from "@/api/team";
import { GradientAvatar } from "@/components/blocks/avatar/gradient-avatar";
import { ProjectAvatar } from "@/components/blocks/avatar/project-avatar";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import {
Select,
@@ -17,98 +13,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { UnderlineLink } from "@/components/ui/UnderlineLink";
import { Fieldset } from "./common";
export type MinimalTeam = Pick<Team, "id" | "name" | "image" | "slug">;
export type MinimalProject = Pick<Project, "id" | "name" | "image" | "slug">;
export type TeamAndProjectSelection = {
team: MinimalTeam | undefined;
project: MinimalProject | undefined;
};
export type MinimalTeamsAndProjects = Array<{
team: MinimalTeam;
projects: MinimalProject[];
}>;
type TeamAndProjectSelectorProps = {
teamsAndProjects: MinimalTeamsAndProjects;
selection: TeamAndProjectSelection;
enabled: boolean;
onSelectionChange: (selection: TeamAndProjectSelection) => void;
client: ThirdwebClient;
onSetEnabled: (enabled: boolean) => void;
};
export function AddToProjectCardUI(props: TeamAndProjectSelectorProps) {
const selectedTeam = props.teamsAndProjects.find(
(t) => t.team.id === props.selection.team?.id,
);
const isProjectSelected = props.selection.project && props.enabled;
return (
<Fieldset
description="Save the deployed contract in a project's contract list on thirdweb dashboard"
headerChildren={
<div className="absolute top-4 right-4 lg:top-6 lg:right-6">
<Checkbox
checked={props.enabled}
className="size-5"
onCheckedChange={(checked) => {
props.onSetEnabled(!!checked);
}}
/>
</div>
}
headerClassName="pr-14"
legend="Add To Project"
>
<div className="flex flex-col gap-5">
{/* Team & Project selectors */}
{props.enabled && (
<AddToProjectSelector
client={props.client}
onSelectionChange={props.onSelectionChange}
selection={props.selection}
teamsAndProjects={props.teamsAndProjects}
/>
)}
{/* No projects alert */}
{selectedTeam?.projects.length === 0 && (
<Alert variant="info">
<CircleAlertIcon className="size-5" />
<AlertTitle> Selected team has no projects </AlertTitle>
<AlertDescription>
<UnderlineLink
className="inline-flex items-center gap-2"
href={`/team/${selectedTeam.team.slug}`}
rel="noopener noreferrer"
target="_blank"
>
Create Project <ExternalLinkIcon className="size-3.5" />
</UnderlineLink>
</AlertDescription>
</Alert>
)}
{/* No project selected alert */}
{!isProjectSelected && (
<Alert variant="warning">
<CircleAlertIcon className="size-5" />
<AlertTitle>No Project Selected</AlertTitle>
<AlertDescription>
Deployed contract will not be saved in thirdweb dashboard
</AlertDescription>
</Alert>
)}
</div>
</Fieldset>
);
}
import type { MinimalTeamsAndProjects, TeamAndProjectSelection } from "./types";
function SlashSeparator() {
return <div className="mx-2 h-5 w-[2px] rotate-[25deg] bg-foreground/20" />;

Some files were not shown because too many files have changed in this diff Show More