-
Notifications
You must be signed in to change notification settings - Fork 162
Release/1.0 - WIP #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Release/1.0 - WIP #242
Conversation
…error fix: resolve corepack signature issue (#221)
…e-code-debug feat: support server side code debugging
…e-code-debug-vscode feat: add launch.json to enable debug mode on vscode
…-empty-accounts feat: allow users delete empty accounts
…epage Feat/add prompt filtering on homepage
…ana and embedded wallets to funding wallets inteface
…nected-wallets feat: enable privy connected wallets to pay EAP
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis pull request introduces multiple configuration updates and new features. It adds entries and files to define the development environment (e.g., Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant AC as AccountContent
participant DAD as DeleteAccountDialog
participant S as Server (deleteUser)
U->>AC: Click "Delete Account"
AC->>DAD: Show deletion confirmation dialog
U->>DAD: Confirm deletion action
DAD->>AC: Trigger delete account process
AC->>S: Call deleteUser API
S-->>AC: Return success or error response
AC->>U: Notify outcome and perform logout on success
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
src/app/(user)/account/account-content.tsxOops! Something went wrong! :( ESLint: 9.18.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. src/app/(user)/account/delete-account-dialog.tsxOops! Something went wrong! :( ESLint: 9.18.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. src/app/(user)/home/home-content.tsxOops! Something went wrong! :( ESLint: 9.18.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
src/app/(user)/account/account-content.tsx (1)
92-105
: 🛠️ Refactor suggestionPotential one-way logic in balance check.
WhenhasBalance
isfalse
,isEmptyAccount
is set totrue
. However, if the user later acquires a balance, this code does not unsetisEmptyAccount
. Consider updating to:- if (!hasBalance) { - setIsEmptyAccount(true); - } + setIsEmptyAccount(!hasBalance);to ensure the flag remains correct as wallet balances change.
🧹 Nitpick comments (11)
src/components/dashboard/app-sidebar.tsx (1)
37-40
: Potential Logic Mismatch in Beta Status Display.
The sidebar header now displays "STABLE" whenIS_BETA
is truthy. Typically, one might expect a beta indicator (e.g., "BETA") when the app is in beta mode. If this change is a deliberate part of the release branding, consider adding an inline comment to clarify the intent and avoid confusion.docker-compose.yml (1)
63-63
: Port mapping change is appropriately documented.Changing the host port from 5432 to 5433 is a good practice to avoid conflicts with local PostgreSQL instances. The comment clearly explains the rationale.
However, there's a trailing space at the end of the comment line that should be removed:
- - "5433:5432" # Map container port to a different host port to prevent conflicts with local postgres instance + - "5433:5432" # Map container port to a different host port to prevent conflicts with local postgres instance🧰 Tools
🪛 YAMLlint (1.35.1)
[error] 63-63: trailing spaces
(trailing-spaces)
local_app_dev.sh (1)
1-12
: New development script properly configures the PostgreSQL connection.The script correctly sets up environment variables for the database connection using port 5433, which is consistent with the docker-compose.yml change. The default credentials are provided but can be overridden through the .env file, which is good for developer flexibility.
Consider adding basic error handling and file permission instructions:
#!/bin/bash +# Ensure PostgreSQL is running before starting the application +if ! nc -z localhost 5433 &>/dev/null; then + echo "Warning: PostgreSQL doesn't appear to be running on port 5433" + echo "Make sure to start Docker containers with: docker-compose up -d" +fi + # change the default POSTGRES_USER and POSTGRES_PASSWORD # to the actual value defined in your .env export POSTGRES_USER=${POSTGRES_USER:-"admin"} export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-"admin"} DB_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5433/neurdb" export DATABASE_URL=$DB_URL export DIRECT_URL=$DB_URL +# Ensure the dev:local script exists +if ! pnpm run --list | grep -q "dev:local"; then + echo "Error: dev:local script not found in package.json" + exit 1 +fi + pnpm run dev:localDon't forget to make the script executable with:
chmod +x local_app_dev.sh
LOCAL_DEV.md (1)
93-110
: Add language specifiers to the code blocks.The markdown fenced code blocks are missing language specifiers, which affects syntax highlighting and is flagged by markdownlint.
-``` +```bash chmod u+x local_app_dev.sh-
+
bash
./local_app_dev.shThe debugging instructions are otherwise clear and helpful for developers who need to debug server-side code.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
97-97: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
103-103: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
src/lib/constants.ts (1)
39-39
: Consider adding documentation for EAP_PRICE.While the constant is straightforward, adding a comment explaining what EAP stands for (Early Access Program) and the purpose of this constant would improve code clarity.
-export const EAP_PRICE = 1.0; +/** Price in SOL for Early Access Program participation */ +export const EAP_PRICE = 1.0;src/app/(user)/account/delete-account-dialog.tsx (2)
16-21
: Fix typo in interface property name.There's a spelling error in the property name "eligibililty" (extra 'l').
interface DeletePromptDialogProps { displayPrompt: boolean; - eligibililty: boolean; + eligibility: boolean; onConfirm: () => void; onCancel: () => void; }
23-28
: Fix typo in component prop name.Ensure the prop name is corrected in the component parameter destructuring as well.
export const DeleteAccountDialog = ({ displayPrompt, - eligibililty, + eligibility, onCancel, onConfirm, }: DeletePromptDialogProps) => {src/hooks/use-wallets.ts (1)
10-27
: Consider adding error logging.
Inside thecatch
block at lines 24-26, you returnundefined
without logging the error. Logging could help with troubleshooting.} catch (error) { + console.error("Failed to retrieve embedded wallet balance:", error); return undefined; }
src/components/dashboard/wallet-card-eap.tsx (1)
1-171
: Overall functionality looks solid.
The wallet card’s logic for funding and paying EAP is well structured. Consider removing or clarifying the commented-out code at line 72 if it’s no longer needed.src/lib/solana/index.ts (1)
132-132
: Avoid usingthis
inside static methods.
Usingthis
in a static context can be confusing. Prefer referencing the class name (SolanaUtils
) directly for clarity.- if (this.isConnectedSolanaWallet(wallet)) { + if (SolanaUtils.isConnectedSolanaWallet(wallet)) { - const balance = await this.connection.getBalance(fromPubkey); + const balance = await SolanaUtils.connection.getBalance(fromPubkey); - const { blockhash } = await this.connection.getLatestBlockhash('confirmed'); + const { blockhash } = await SolanaUtils.connection.getLatestBlockhash('confirmed'); - const signature = await this.connection.sendRawTransaction(signedTransaction.serialize(), ...); + const signature = await SolanaUtils.connection.sendRawTransaction(signedTransaction.serialize(), ...); - const balance = await this.connection.getBalance(fromPubkey); + const balance = await SolanaUtils.connection.getBalance(fromPubkey);Also applies to: 145-145, 177-177, 185-185, 223-223
🧰 Tools
🪛 Biome (1.9.4)
[error] 132-132: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.(lint/complexity/noThisInStatic)
src/app/(user)/account/account-content.tsx (1)
316-327
: Avatar and user info rendering.
Displays user’s Twitter profile picture if available; fallback logic is correct. Optional: include analt
attribute for accessibility on theAvatarImage
.<AvatarImage src={userData.twitter?.profilePictureUrl || undefined} + alt="User avatar" className="rounded-lg object-cover" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (27)
.gitignore
(1 hunks).nvmrc
(1 hunks).vscode/launch.json
(1 hunks).vscode/settings.json
(1 hunks)Dockerfile.local
(1 hunks)LOCAL_DEV.md
(2 hunks)docker-compose.yml
(1 hunks)local_app_dev.sh
(1 hunks)package.json
(3 hunks)src/app/(user)/account/account-content.tsx
(11 hunks)src/app/(user)/account/delete-account-dialog.tsx
(1 hunks)src/app/(user)/home/components/select-funding-wallet.tsx
(1 hunks)src/app/(user)/home/data/funding-wallets.ts
(1 hunks)src/app/(user)/home/home-content.tsx
(10 hunks)src/app/(user)/saved-prompts/components/filter-dropdown.tsx
(3 hunks)src/app/(user)/saved-prompts/page.tsx
(2 hunks)src/components/dashboard/app-sidebar.tsx
(1 hunks)src/components/dashboard/wallet-card-eap.tsx
(1 hunks)src/components/dashboard/wallet-card.tsx
(4 hunks)src/components/provider-auth.tsx
(2 hunks)src/components/transfer-dialog.tsx
(1 hunks)src/components/ui/checkbox.tsx
(1 hunks)src/hooks/use-wallets.ts
(2 hunks)src/lib/constants.ts
(2 hunks)src/lib/solana/index.ts
(5 hunks)src/server/actions/ai.ts
(3 hunks)src/server/actions/user.ts
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/components/dashboard/wallet-card.tsx (2)
src/types/db.ts (1)
EmbeddedWallet
(12-22)src/lib/constants.ts (1)
solanaCluster
(43-45)
src/app/(user)/home/components/select-funding-wallet.tsx (8)
src/types/db.ts (1)
EmbeddedWallet
(12-22)src/app/(user)/home/data/funding-wallets.ts (3)
FundingWallet
(7-12)SolanaConnectedFundingWallet
(31-41)EmbeddedFundingWallet
(17-29)src/hooks/use-wallets.ts (1)
useEmbeddedWallets
(29-39)src/hooks/use-user.ts (1)
useUser
(122-230)src/components/ui/dialog.tsx (5)
Dialog
(113-113)DialogContent
(118-118)DialogHeader
(119-119)DialogTitle
(121-121)DialogDescription
(122-122)src/lib/utils.ts (1)
cn
(17-19)src/components/dashboard/wallet-card-eap.tsx (1)
WalletCardEap
(29-171)src/lib/constants.ts (1)
solanaCluster
(43-45)
src/app/(user)/home/data/funding-wallets.ts (3)
src/types/helius/fungibleToken.ts (1)
FungibleToken
(8-23)src/types/helius/nonFungibleToken.ts (1)
NonFungibleToken
(5-20)src/types/db.ts (1)
EmbeddedWallet
(12-22)
src/app/(user)/account/delete-account-dialog.tsx (4)
src/components/ui/dialog.tsx (5)
Dialog
(113-113)DialogContent
(118-118)DialogHeader
(119-119)DialogTitle
(121-121)DialogFooter
(120-120)src/components/ui/checkbox.tsx (1)
Checkbox
(39-39)src/components/ui/label.tsx (1)
Label
(27-27)src/components/ui/button.tsx (1)
Button
(58-58)
src/components/provider-auth.tsx (1)
src/lib/constants.ts (2)
solanaCluster
(43-45)RPC_URL
(9-11)
src/hooks/use-wallets.ts (3)
src/types/db.ts (1)
EmbeddedWallet
(12-22)src/lib/solana/helius.ts (1)
searchWalletAssets
(97-270)src/types/helius/portfolio.ts (1)
SOL_MINT
(4-4)
src/components/ui/checkbox.tsx (1)
src/lib/utils.ts (1)
cn
(17-19)
src/app/(user)/account/account-content.tsx (3)
src/hooks/use-wallets.ts (1)
hasWalletWithBalance
(41-46)src/app/(user)/account/delete-account-dialog.tsx (1)
DeleteAccountDialog
(23-109)src/server/actions/user.ts (1)
deleteUser
(319-363)
src/lib/constants.ts (1)
src/app/(user)/saved-prompts/types/prompt.ts (1)
FilterOption
(1-4)
src/components/dashboard/wallet-card-eap.tsx (7)
src/app/(user)/home/data/funding-wallets.ts (1)
FundingWallet
(7-12)src/lib/solana/helius.ts (1)
searchWalletAssets
(97-270)src/types/helius/portfolio.ts (1)
SOL_MINT
(4-4)src/components/ui/copyable-text.tsx (1)
CopyableText
(17-68)src/components/ui/skeleton.tsx (1)
Skeleton
(15-15)src/lib/constants.ts (1)
EAP_PRICE
(39-39)src/components/ui/button.tsx (1)
Button
(58-58)
🪛 markdownlint-cli2 (0.17.2)
LOCAL_DEV.md
97-97: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
103-103: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🪛 Biome (1.9.4)
src/lib/solana/index.ts
[error] 132-132: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 145-145: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 177-177: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 185-185: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
[error] 223-223: Using this in a static context can be confusing.
this refers to the class.
Unsafe fix: Use the class name instead.
(lint/complexity/noThisInStatic)
🪛 YAMLlint (1.35.1)
docker-compose.yml
[error] 63-63: trailing spaces
(trailing-spaces)
🔇 Additional comments (68)
.nvmrc (1)
1-1
: Node.js Version Specification Looks Good.
The file correctly specifies the Node.js version asv20.18.1
, which should help maintain consistent development environments..gitignore (1)
45-46
: Appropriate Addition of.idea
to Ignore List.
Including.idea
ensures that JetBrains IDE configuration files are not committed. This is a good practice for keeping the repository clean.src/components/transfer-dialog.tsx (1)
68-68
: Improved Readability with Blank Line Addition.
The insertion of a blank line after thetransactionResult
state declaration enhances readability without affecting functionality..vscode/settings.json (1)
3-3
: Review the Editor Formatting Setting Change.
Changing"editor.formatOnSave"
fromtrue
tofalse
disables automatic formatting on save. Please confirm that this change is intentional and aligns with the team’s coding standards or formatting workflow.Dockerfile.local (1)
4-7
: Good addition to prevent Corepack signature issues.Adding the latest Corepack installation step ensures the application will use the correct package manager without encountering outdated signature issues. The comment with the reference documentation link provides helpful context for this change.
src/app/(user)/saved-prompts/components/filter-dropdown.tsx (4)
24-30
: Well-typed props extension for increased component reusability.Adding the optional
displayAtHomePage
property enhances the component's flexibility to be used in different contexts.
32-38
: Good default value provided for new optional prop.Setting a sensible default value for
displayAtHomePage
ensures the component maintains its original behavior when the prop isn't explicitly provided.
45-54
: Responsive styling based on display context.The conditional Button variant and className changes provide appropriate styling based on the component's context, which improves UX consistency.
59-68
: Appropriate icon selection based on component context.The conditional rendering of different icons (ChevronUp/ChevronDown vs Filter) based on the displayAtHomePage property and open state enhances the UX by providing appropriate visual cues in each context.
src/components/ui/checkbox.tsx (1)
1-39
: Well-implemented Checkbox component using Radix UI primitives.The Checkbox component is well-structured and follows React best practices:
- Uses forwardRef to properly handle ref forwarding
- Correctly extends Radix UI's CheckboxPrimitive.Root props
- Properly handles the checked state and callback
- Includes displayName for better debugging
- Uses the cn utility to combine class names
The implementation is clean, accessible, and reusable across the application.
src/components/provider-auth.tsx (2)
4-4
: LGTM: Added SolanaCluster type import.This import is necessary for the type definition used in the solanaCluster constant.
40-40
: LGTM: Updated solanaClusters configuration.Good change to use the environment-specific solanaCluster configuration.
LOCAL_DEV.md (1)
61-61
: LGTM: Added clear instructions for Privy configuration.This comment provides valuable guidance for configuring Privy's server-side access.
src/app/(user)/saved-prompts/page.tsx (2)
12-12
: LGTM: Good refactoring to centralize filterOptions.Moving the filterOptions to a constants file improves maintainability and reusability.
380-380
: LGTM: Added truncate class for better UI.Adding the 'truncate' class ensures that long prompt content is properly truncated with an ellipsis, improving the visual consistency of the UI.
src/server/actions/ai.ts (4)
136-138
: Enhancement to utilize custom Helius RPC URL.Good improvement to conditionally include the HELIUS_RPC_URL in the configuration when available in the environment. This provides more flexibility for different deployment environments.
152-152
: Well-structured schema update for memo field.The addition of the optional memo field to the transferToken schema is properly typed and documented with a clear description.
156-163
: Properly updated destructuring for new memo parameter.The destructuring pattern has been correctly updated to include the new memo property, maintaining alignment with the schema update.
177-177
: Appropriate implementation of memo feature.The memo parameter is now correctly passed to the agent.transfer method, enabling the annotation of token transfers.
.vscode/launch.json (1)
1-34
: Well-structured debugging configuration for VS Code.This configuration provides a comprehensive setup for both server-side and client-side debugging, with a compound configuration for full-stack debugging. The source map path overrides are correctly configured to properly map compiled paths back to the source code.
Key features implemented:
- Server-side Node.js debugging on port 9230
- Client-side Chrome debugging pointing to localhost:3001
- Full-stack debugging setup through the compound configuration
- Appropriate source map path overrides for turbopack
src/components/dashboard/wallet-card.tsx (4)
27-27
: Good practice using centralized constants.Importing the solanaCluster constant instead of hardcoding cluster values improves maintainability and consistency across the application.
36-36
: Enhanced component flexibility with disableFund property.Adding this property allows better control over the wallet card's funding functionality.
114-114
: Improved code maintainability.Using the solanaCluster constant instead of hardcoding the cluster name makes the code more maintainable and ensures consistency across environments.
200-215
: Enhanced user experience with contextual feedback.Good improvement to add a tooltip explaining why funding might be disabled and updating the Button's disabled state accordingly. This provides users with important context about functionality limitations.
src/server/actions/user.ts (2)
329-345
: Good user validation and early access handling.The implementation correctly checks if the user exists and prevents deletion of accounts with active early access, providing a clear error message directing users to support.
347-353
: Proper transaction handling for data integrity.Using a database transaction to delete both wallets and the user record ensures data consistency is maintained during the deletion process.
src/lib/constants.ts (4)
1-4
: Appropriate import additions.The imports for
FilterOption
andSolanaCluster
are correctly added to support the new constants defined in this file.
17-38
: Well-structured filter options.The
filterOptions
array is well-typed and properly implements theFilterOption
interface from the imported type. The structured approach to defining filter options in constants rather than locally in components improves maintainability.
41-45
: Environment-aware Solana cluster configuration.Good implementation of conditional logic to determine the Solana cluster based on the environment variable. This supports proper development and production environments.
47-47
: LGTM: Wallet selection constant.The constant
PHANTOM_WALLET_SELECT
is appropriately defined for wallet selection functionality.package.json (4)
3-3
: Major version update indicates significant changes.Updating to version 1.0.0 signifies a production-ready release, which aligns with the PR objective of preparing for production deployment.
8-8
: Enhanced local development setup.The new
dev:local
script with debugging options and a different port (3001) allows for better development workflow alongside other services.
31-31
: Dependency added for checkbox component.Addition of
@radix-ui/react-checkbox
supports the new checkbox functionality used in the account deletion dialog.
79-79
:❓ Verification inconclusive
Verify the impact of changing the solana-agent-kit dependency.
The source for
solana-agent-kit
has changed fromslimeonmyhead/solana-agent-kit
torobertqin86/solana-agent-kit
with a different commit hash. This change could potentially affect wallet functionality, including the new account deletion feature.
🏁 Script executed:
#!/bin/bash # Check for breaking changes between the old and new solana-agent-kit versions # Clone the old repository (if accessible) echo "Attempting to clone the old repository version..." git clone https://github.com/slimeonmyhead/solana-agent-kit.git old-solana-agent-kit 2>/dev/null cd old-solana-agent-kit 2>/dev/null && git checkout c571e8b59ed7d399a705578af2d58c95f7e9e826 2>/dev/null && cd .. || echo "Could not access old repository" # Clone the new repository echo "Cloning the new repository version..." git clone https://github.com/robertqin86/solana-agent-kit.git new-solana-agent-kit cd new-solana-agent-kit && git checkout f9ba5bfada0ce60527f2641989de553075e24785 && cd .. # Check for API differences (if both repos are accessible) echo "Checking for package.json changes between versions:" if [ -d "old-solana-agent-kit" ] && [ -d "new-solana-agent-kit" ]; then diff -u old-solana-agent-kit/package.json new-solana-agent-kit/package.json || echo "Package differences found" # Check for exported functions relevant to user deletion echo "Checking for user-related functionality changes:" grep -r "deleteUser\|user" new-solana-agent-kit/src/ --include="*.ts" -A 5 -B 5 else echo "Could only access the new repository. Examining relevant functionality:" grep -r "deleteUser\|user" new-solana-agent-kit/src/ --include="*.ts" -A 5 -B 5 fiLength of output: 100535
Dependency update: New solana-agent-kit version appears API-compatible, though further testing is advisable.
- The diff in package.json only shows an added
"packageManager"
field.- Searching the new repository confirms that user-related functions (e.g., a
deleteUserProfile
capability) are present.- No overt breaking changes in wallet functionality were detected; however, it is recommended to perform end-to-end testing—especially for the account deletion feature—to ensure all wallet flows remain unaffected.
src/app/(user)/home/data/funding-wallets.ts (4)
1-5
: Appropriate imports for wallet functionality.The imports are correctly set up for the wallet interfaces and classes that follow.
7-16
: Well-defined interfaces for funding wallets.The
FundingWallet
andWalletPortfolio
interfaces provide clear contracts for wallet implementations with appropriate properties and types.
17-29
: EmbeddedFundingWallet implementation looks good.The class properly implements the
FundingWallet
interface with readonly properties for immutability. The constructor correctly initializes properties from the providedEmbeddedWallet
.Consider initializing the optional
walletPortfolio
property in the constructor for completeness:constructor(embeddedWallet: EmbeddedWallet) { this.id = embeddedWallet.id; this.name = embeddedWallet.name; this.publicKey = embeddedWallet.publicKey; + this.walletPortfolio = undefined; // Explicitly initialize optional property }
31-41
: SolanaConnectedFundingWallet implementation is correct.The class properly implements the
FundingWallet
interface and correctly initializes properties from theConnectedSolanaWallet
. Using the wallet address as the ID makes sense for Solana wallets.Note that the
walletPortfolio
property is not declared in this class, though it's optional in the interface. For consistency withEmbeddedFundingWallet
, consider adding it:export class SolanaConnectedFundingWallet implements FundingWallet { public readonly id: string; public readonly name: string; public readonly publicKey: string; + public walletPortfolio?: WalletPortfolio; constructor(solanaConnectedWallet: ConnectedSolanaWallet) { this.id = solanaConnectedWallet.address; this.name = solanaConnectedWallet.meta.name; this.publicKey = solanaConnectedWallet.address; } }
src/app/(user)/account/delete-account-dialog.tsx (2)
36-77
: Well-implemented account deletion confirmation flow.The component correctly implements a confirmation flow with clear warnings about the irreversible nature of account deletion. The checkbox requirement prevents accidental deletion, and the disabled button until confirmation is a good safety measure.
78-104
: Clear messaging for ineligible account deletion.The alternate UI for ineligible users provides clear explanations about why account deletion isn't possible and offers appropriate next steps through Discord support.
src/hooks/use-wallets.ts (2)
5-8
: Imports look good.
No issues detected with these newly added import statements.
41-46
: Double-check handling ofundefined
balances.
IfgetEmbeddedWalletBalance
returnsundefined
(due to an error),hasWalletWithBalance
immediately returnstrue
. Verify if considering an error as a valid “has balance” scenario is intentional or if it should be treated as having zero balance.src/app/(user)/home/components/select-funding-wallet.tsx (1)
1-177
: Great addition for wallet selection dialog.
The integration of embedded and external wallets is well implemented, and there are no apparent issues with the approach or the data flow.src/app/(user)/account/account-content.tsx (11)
3-3
: Additions to React imports look good.
They appear to be used appropriately for transitioning and optimistic updates.
18-18
: Unused import from 'lodash'.
Currently,set
from 'lodash' is not referenced anywhere. The coding guidelines advise ignoring unused imports unless flagged by tools, so no immediate action is required.
40-40
: ImportinghasWalletWithBalance
anduseEmbeddedWallets
.
These hooks are utilized to fetch and evaluate wallet data. The usage appears logically consistent.
54-58
: Imports for new user actions.
Bringing indeleteUser
andupdateUser
fromuser.ts
aligns with the new account deletion functionality.
61-61
: NewDeleteAccountDialog
import.
This integration looks consistent with the code that triggers the dialog.
68-69
: New state variables.
isEmptyAccount
anddisplayPrompt
are straightforward booleans used to control account deletion checks and dialog visibility. The naming is clear.
71-77
:isDeleting
and wallet context setup.
The addition ofisDeleting
cleanly solves the loading state during account deletion. Fetching embedded wallets viauseEmbeddedWallets
is also appropriate.
89-89
: Addinglogout
to user context.
This is essential for finalizing account deletion and session cleanup.
209-210
: Early return with loading or deleting states.
Displaying<LoadingStateSkeleton />
is consistent with typical UI patterns.
289-310
: Account deletion flow.
The dialog’sonConfirm
implementation handles the loading state, toast messages, and error handling. This is a solid approach that informs the user about the deletion process.
339-347
: 'Delete Account' button placement looks fine.
Button styling is consistent with the destructive action. No issues found.src/app/(user)/home/home-content.tsx (14)
9-10
: New imports from@privy-io/react-auth
.
AddingConnectedSolanaWallet
anduseConnectWallet
is coherent with the wallet connection logic introduced below.
14-14
: AddingCheckCircle2
,Dot
,Loader2
fromlucide-react
.
Useful for icons, pagination indicators, and loading states.
28-29
:filterOptions
andEAP_PRICE
imports.
Consolidating constants inconstants.ts
is good practice for maintainable configuration.
44-44
:EmbeddedWallet
type usage.
Indicates new functionalities around local wallet objects. No issues identified.
46-47
: Importing filter components and types.
FilterDropdown
andFilterValue
enable dynamic prompt filtering. Implementation aligns with the newly introduced filtering logic.
49-49
:SelectFundingWalletDialog
import.
Prepares a wallet selection dialog to handle purchase or funding flows.
51-51
: Funding wallet data import.
Allows specifying which wallet covers transaction fees or purchase amounts.
82-82
: New pagination index.
Used to support pagination for saved prompts. Straightforward approach to chunking results.
85-85
: Addingfilter
state.
This complements theFilterDropdown
and enables various sorting/filtering strategies on prompts.
94-94
:displayPrompt
state.
Manages the visibility of the wallet funding or purchase dialog. Matches the user flow.
287-288
:handlePurchaseOptions
function.
Simplifies user experience by settingdisplayPrompt
totrue
on purchase flow entry.
291-356
: ExpandedhandlePurchase
logic.
Accepts bothWallet
andFundingWallet
for a flexible Solana transfer. Includes memo usage, error handling, and toast notifications. Overall well-structured, though ensure you have test coverage to confirm transaction reliability.
597-605
:SelectFundingWalletDialog
integration.
Displays the new prompt for EAP purchases, allowing the user to pick the funding source or connect externally. Behavior appears cohesive with the rest of the purchase flow.
665-665
:onClick={handlePurchaseOptions}
on EAP button.
Triggers the new purchase dialog. Straightforward and consistent naming.
const isDev = process.env.NEXT_PUBLIC_DEV === 'true'; | ||
|
||
const solanaCluster: SolanaCluster = isDev | ||
? { name: 'devnet', rpcUrl: process.env.NEXT_PUBLIC_HELIUS_RPC_URL! } | ||
: { name: 'mainnet-beta', rpcUrl: RPC_URL }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider adding a fallback for the RPC URL in development mode.
The non-null assertion operator (!
) on line 13 assumes that process.env.NEXT_PUBLIC_HELIUS_RPC_URL
will always be defined in development mode. This could lead to runtime errors if the environment variable is missing.
const solanaCluster: SolanaCluster = isDev
- ? { name: 'devnet', rpcUrl: process.env.NEXT_PUBLIC_HELIUS_RPC_URL! }
+ ? { name: 'devnet', rpcUrl: process.env.NEXT_PUBLIC_HELIUS_RPC_URL || 'https://api.devnet.solana.com' }
: { name: 'mainnet-beta', rpcUrl: RPC_URL };
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const isDev = process.env.NEXT_PUBLIC_DEV === 'true'; | |
const solanaCluster: SolanaCluster = isDev | |
? { name: 'devnet', rpcUrl: process.env.NEXT_PUBLIC_HELIUS_RPC_URL! } | |
: { name: 'mainnet-beta', rpcUrl: RPC_URL }; | |
const isDev = process.env.NEXT_PUBLIC_DEV === 'true'; | |
const solanaCluster: SolanaCluster = isDev | |
? { name: 'devnet', rpcUrl: process.env.NEXT_PUBLIC_HELIUS_RPC_URL || 'https://api.devnet.solana.com' } | |
: { name: 'mainnet-beta', rpcUrl: RPC_URL }; |
export async function deleteUser() { | ||
try { | ||
const authResult = await verifyUser(); | ||
const userId = authResult?.data?.data?.id; | ||
const privyId = authResult?.data?.data?.privyId; | ||
|
||
if (!userId) { | ||
return { success: false, error: 'UNAUTHORIZED' }; | ||
} | ||
|
||
// check eap status is active | ||
const user = await prisma.user.findUnique({ | ||
where: { id: userId }, | ||
}); | ||
|
||
if (!user) { | ||
return { success: false, error: 'User not found' }; | ||
} | ||
|
||
const { earlyAccess } = user; | ||
if (earlyAccess) { | ||
return { | ||
success: false, | ||
error: | ||
'Cannot delete user with active early access. Please reach out to support at our official discord channel.', | ||
}; | ||
} | ||
|
||
const deleteUser = prisma.user.delete({ where: { id: userId } }); | ||
const deleteWallets = prisma.wallet.deleteMany({ | ||
where: { ownerId: userId }, | ||
}); | ||
|
||
await prisma.$transaction([deleteWallets, deleteUser]); | ||
if (privyId) { | ||
await PRIVY_SERVER_CLIENT.deleteUser(privyId); | ||
} | ||
return { | ||
success: true, | ||
}; | ||
} catch (error) { | ||
console.error('Error updating user:', error); | ||
return { success: false, error: 'Failed to delete user' }; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
User deletion functionality properly implemented.
The function provides a comprehensive approach to user deletion, including validation, early access checking, and proper transaction handling for data integrity.
Two improvements to consider:
- The error message in the catch block refers to "Error updating user:" but should say "Error deleting user:" to match the actual operation:
- console.error('Error updating user:', error);
+ console.error('Error deleting user:', error);
- Consider enhancing error handling for the Privy client deletion:
await prisma.$transaction([deleteWallets, deleteUser]);
if (privyId) {
- await PRIVY_SERVER_CLIENT.deleteUser(privyId);
+ try {
+ await PRIVY_SERVER_CLIENT.deleteUser(privyId);
+ } catch (privyError) {
+ console.error('Error deleting user from Privy:', privyError);
+ // User is already deleted from our DB, so still return success
+ // but log the error for monitoring
+ }
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export async function deleteUser() { | |
try { | |
const authResult = await verifyUser(); | |
const userId = authResult?.data?.data?.id; | |
const privyId = authResult?.data?.data?.privyId; | |
if (!userId) { | |
return { success: false, error: 'UNAUTHORIZED' }; | |
} | |
// check eap status is active | |
const user = await prisma.user.findUnique({ | |
where: { id: userId }, | |
}); | |
if (!user) { | |
return { success: false, error: 'User not found' }; | |
} | |
const { earlyAccess } = user; | |
if (earlyAccess) { | |
return { | |
success: false, | |
error: | |
'Cannot delete user with active early access. Please reach out to support at our official discord channel.', | |
}; | |
} | |
const deleteUser = prisma.user.delete({ where: { id: userId } }); | |
const deleteWallets = prisma.wallet.deleteMany({ | |
where: { ownerId: userId }, | |
}); | |
await prisma.$transaction([deleteWallets, deleteUser]); | |
if (privyId) { | |
await PRIVY_SERVER_CLIENT.deleteUser(privyId); | |
} | |
return { | |
success: true, | |
}; | |
} catch (error) { | |
console.error('Error updating user:', error); | |
return { success: false, error: 'Failed to delete user' }; | |
} | |
} | |
export async function deleteUser() { | |
try { | |
const authResult = await verifyUser(); | |
const userId = authResult?.data?.data?.id; | |
const privyId = authResult?.data?.data?.privyId; | |
if (!userId) { | |
return { success: false, error: 'UNAUTHORIZED' }; | |
} | |
// check eap status is active | |
const user = await prisma.user.findUnique({ | |
where: { id: userId }, | |
}); | |
if (!user) { | |
return { success: false, error: 'User not found' }; | |
} | |
const { earlyAccess } = user; | |
if (earlyAccess) { | |
return { | |
success: false, | |
error: | |
'Cannot delete user with active early access. Please reach out to support at our official discord channel.', | |
}; | |
} | |
const deleteUser = prisma.user.delete({ where: { id: userId } }); | |
const deleteWallets = prisma.wallet.deleteMany({ | |
where: { ownerId: userId }, | |
}); | |
await prisma.$transaction([deleteWallets, deleteUser]); | |
if (privyId) { | |
try { | |
await PRIVY_SERVER_CLIENT.deleteUser(privyId); | |
} catch (privyError) { | |
console.error('Error deleting user from Privy:', privyError); | |
// User is already deleted from our DB, so still return success | |
// but log the error for monitoring | |
} | |
} | |
return { | |
success: true, | |
}; | |
} catch (error) { | |
console.error('Error deleting user:', error); | |
return { success: false, error: 'Failed to delete user' }; | |
} | |
} |
if (privyId) { | ||
await PRIVY_SERVER_CLIENT.deleteUser(privyId); | ||
} | ||
return { | ||
success: true, | ||
}; | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Consider resilience for external service failure.
The current implementation doesn't handle the case where the database deletion succeeds but Privy deletion fails. This could lead to inconsistency between your systems.
Run this script to check if there are any additional user-related records that should be included in the deletion transaction:
🏁 Script executed:
#!/bin/bash
# Check for other tables with foreign keys to the user table
grep -r "ownerId\|userId\|user_id\|owner_id" --include="*.prisma" .
Length of output: 1326
Ensure Consistent and Resilient User Deletion
- The current deletion logic in
src/server/actions/user.ts
only attempts to delete the user from the external Privy service (viaPRIVY_SERVER_CLIENT.deleteUser(privyId)
) without a fallback if that call fails. - Our Prisma schema reveals several associations referencing the user (via
userId
,ownerId
, etc.), which means that if the external deletion fails while the database deletion succeeds, the system may become inconsistent. - Consider refactoring the deletion flow to handle external service failures gracefully. Options might include:
- Reordering operations (e.g., performing the external deletion first and only committing the internal deletion upon success).
- Implementing a rollback or compensatory mechanism in the event of an external deletion failure.
- Adding robust error handling and logging to manage and possibly retry the external deletion.
<div className="flex items-center gap-2"> | ||
<Checkbox | ||
id="ack-checkbox" | ||
onCheckedChange={(checked) => setAckChecked(checked)} | ||
/> | ||
<Label | ||
htmlFor="ack-checkbox" | ||
className="cursor-pointer text-sm leading-snug" | ||
> | ||
I confirm that my wallets are empty and I understand this action | ||
is irreversible. | ||
</Label> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Reset checkbox state when dialog closes.
Currently, if a user opens the dialog, checks the box, then cancels and reopens the dialog, the checkbox state persists. Consider resetting it when the dialog closes for better security.
export const DeleteAccountDialog = ({
displayPrompt,
eligibililty,
onCancel,
onConfirm,
}: DeletePromptDialogProps) => {
const [ackChecked, setAckChecked] = useState(false);
+
+ // Reset checkbox when dialog closes
+ const handleOpenChange = (open: boolean) => {
+ if (!open) {
+ setAckChecked(false);
+ onCancel();
+ }
+ };
return (
- <Dialog onOpenChange={onCancel} open={displayPrompt}>
+ <Dialog onOpenChange={handleOpenChange} open={displayPrompt}>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<div className="flex items-center gap-2"> | |
<Checkbox | |
id="ack-checkbox" | |
onCheckedChange={(checked) => setAckChecked(checked)} | |
/> | |
<Label | |
htmlFor="ack-checkbox" | |
className="cursor-pointer text-sm leading-snug" | |
> | |
I confirm that my wallets are empty and I understand this action | |
is irreversible. | |
</Label> | |
</div> | |
export const DeleteAccountDialog = ({ | |
displayPrompt, | |
eligibililty, | |
onCancel, | |
onConfirm, | |
}: DeletePromptDialogProps) => { | |
const [ackChecked, setAckChecked] = useState(false); | |
// Reset checkbox when dialog closes | |
const handleOpenChange = (open: boolean) => { | |
if (!open) { | |
setAckChecked(false); | |
onCancel(); | |
} | |
}; | |
return ( | |
<Dialog onOpenChange={handleOpenChange} open={displayPrompt}> | |
<div className="flex items-center gap-2"> | |
<Checkbox | |
id="ack-checkbox" | |
onCheckedChange={(checked) => setAckChecked(checked)} | |
/> | |
<Label | |
htmlFor="ack-checkbox" | |
className="cursor-pointer text-sm leading-snug" | |
> | |
I confirm that my wallets are empty and I understand this action | |
is irreversible. | |
</Label> | |
</div> | |
</Dialog> | |
); | |
}; |
Until subscriptions are rolled out and we're out of EAP, I think the version should still be < 1.0 (ie. 0.3.5) |
This will be the release cut from
beta
that contains all the latest changes that we want to release to production.TODO: Add changelog
Summary by CodeRabbit