Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a referral rewards feature: capture referral codes from URLs, persist them client-side, include refs in signin payloads, provide rewards APIs and a new Rewards & Referral UI, enable Pi SDK sandbox mode, add license/trademark text, and small profile/navigation and metadata updates. Changes
Sequence DiagramsequenceDiagram
participant User as User / Browser
participant RefCapture as RefCapture
participant Storage as SessionStorage
participant Hook as useUserProfile
participant AuthAPI as Auth API
participant RewardsPage as Rewards Page / Rewards API
User->>RefCapture: Load page with ?ref=CODE
RefCapture->>Storage: storeReferralRef(CODE)
User->>Hook: Trigger signin flow
Hook->>Storage: getStoredReferralRef()
Hook->>AuthAPI: signIn(payload + ref)
AuthAPI->>AuthAPI: process sign in and persist backend user
AuthAPI->>Hook: signIn success
Hook->>Storage: getStoredReferralRef(clearAfter=true) (clears)
User->>RewardsPage: Navigate to /profile/rewards
RewardsPage->>AuthAPI: verify auth
RewardsPage->>RewardsPage: call getRewards(), getRewardsTransactions()
RewardsPage->>User: render rewards, referral link, transactions
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
lib/api/rewards.ts (1)
3-3: Duplicated referral storage logic withcomponents/ref-capture.tsx.Both this file and
components/ref-capture.tsxdefine the same storage key (zyradex_referral_ref) and similar storage functions. This creates maintenance overhead and potential for the keys to drift apart.Consider consolidating these utilities in one place:
- Either export
storeReferralRefandgetStoredReferralReffrom this file and use them inRefCapture, or- Move all referral storage logic to
ref-capture.tsxand import from there.♻️ Option: Update ref-capture.tsx to use the rewards.ts utilities
In
components/ref-capture.tsx:"use client" import { useEffect } from "react" +import { storeReferralRef, getStoredReferralRef } from "@/lib/api/rewards" -const REF_STORAGE_KEY = "zyradex_referral_ref" - export function RefCapture() { useEffect(() => { if (typeof window === "undefined") return const params = new URLSearchParams(window.location.search) const ref = params.get("ref") if (ref && ref.trim() !== "") { - sessionStorage.setItem(REF_STORAGE_KEY, ref.trim()) + storeReferralRef(ref) } }, []) return null } -export function getStoredRef(): string | null { - if (typeof window === "undefined") return null - return sessionStorage.getItem(REF_STORAGE_KEY) -} +export const getStoredRef = () => getStoredReferralRef(false) -export function clearStoredRef(): void { - if (typeof window === "undefined") return - sessionStorage.removeItem(REF_STORAGE_KEY) -} +export const clearStoredRef = () => { getStoredReferralRef(true) }Also applies to: 63-78
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/rewards.ts` at line 3, Duplicate referral storage logic exists: extract and centralize the storage key and helper functions by exporting REFERRAL_STORAGE_KEY, storeReferralRef, and getStoredReferralRef from lib/api/rewards.ts and update components/RefCapture (RefCapture) to import and use those exports instead of redefining the key or functions; alternatively, move the same exports into components/ref-capture.tsx and import them from there—choose one location and update all references so a single source of truth (REFERRAL_STORAGE_KEY, storeReferralRef, getStoredReferralRef) is used across the codebase.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/layout.tsx`:
- Line 38: The Pi SDK init call currently hardcodes sandbox: true in the
window.Pi.init invocation; change it to use the same environment-based flag used
elsewhere (e.g., replace the literal with the shared env/config variable used in
pi-provider.tsx or the global CONFIG/PI_SANDBOX flag) so all initialization
points (window.Pi.init in layout.tsx and the init in pi-provider.tsx) read from
the same runtime environment variable; locate the window.Pi.init({ version:
"2.0", sandbox: true }) call and substitute the literal with the shared boolean
(process.env.NEXT_PUBLIC_PI_SANDBOX or the existing helper/constant used in the
other file) and ensure it's parsed to a boolean if necessary.
In `@app/profile/rewards/page.tsx`:
- Around line 45-53: The handleCopyLink function calls
navigator.clipboard.writeText but doesn't await or handle failures; update
handleCopyLink to await navigator.clipboard.writeText(rewards.referralLink) and
wrap it in try/catch so the success toast (toast title "Copied!") is only shown
on successful completion, and show an error toast (e.g., title "Copy failed"
with a helpful message) when the promise rejects; keep references to
rewards?.referralLink, navigator.clipboard.writeText, and toast when making this
change.
In `@components/providers/pi-provider.tsx`:
- Line 173: The hardcoded sandbox flag in window.Pi.init({ version: "2.0",
sandbox: true }) should be driven by the same environment-based configuration
used in authenticate/createPayment; replace the literal true with a shared
boolean (e.g., a NEXT_PUBLIC_PI_SANDBOX or isPiSandbox variable) and wire that
into window.Pi.init and into createPayment/authenticate so both functions use
the same env-derived value for sandbox mode.
- Line 74: The Pi SDK is being initialized with sandbox: true in window.Pi.init
(appears in the Pi provider and the app layout), forcing test-only transactions;
change the init calls to read a public env var (e.g., NEXT_PUBLIC_PI_SANDBOX)
and pass a boolean based on its value instead of the hardcoded true so
production can opt out of sandbox mode; update every place that calls
window.Pi.init (the Pi provider initialization and the layout/init paths
referenced in the review) to use the same environment-driven flag and ensure the
value is parsed as a boolean before passing to sandbox.
In `@hooks/useUserProfile.ts`:
- Around line 41-49: The useEffect in useUserProfile.ts that reads
URLSearchParams and calls storeReferralRef duplicates RefCapture (rendered in
app/layout.tsx) and should be removed; update useUserProfile to no longer
capture ?ref from window.location in the useEffect block and instead rely on
RefCapture to populate storage, keeping only logic that reads the stored
referral during signin (refer to storeReferralRef and any signin-related
functions in this hook) to avoid double-writes and race conditions.
---
Nitpick comments:
In `@lib/api/rewards.ts`:
- Line 3: Duplicate referral storage logic exists: extract and centralize the
storage key and helper functions by exporting REFERRAL_STORAGE_KEY,
storeReferralRef, and getStoredReferralRef from lib/api/rewards.ts and update
components/RefCapture (RefCapture) to import and use those exports instead of
redefining the key or functions; alternatively, move the same exports into
components/ref-capture.tsx and import them from there—choose one location and
update all references so a single source of truth (REFERRAL_STORAGE_KEY,
storeReferralRef, getStoredReferralRef) is used across the codebase.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2c5eab19-9d96-4485-97ff-f3e680dff04c
⛔ Files ignored due to path filters (1)
public/logo.jpgis excluded by!**/*.jpg
📒 Files selected for processing (11)
LICENSEREADME.mdapp/layout.tsxapp/profile/page.tsxapp/profile/rewards/page.tsxcomponents/disclaimer-popup.tsxcomponents/providers/pi-provider.tsxcomponents/ref-capture.tsxhooks/useUserProfile.tslib/api/auth.tslib/api/rewards.ts
💤 Files with no reviewable changes (1)
- README.md
| if (window.Pi) { | ||
| console.log('Pi SDK loaded, initializing...'); | ||
| window.Pi.init({ version: "2.0" }); | ||
| window.Pi.init({ version: "2.0", sandbox: true }); |
There was a problem hiding this comment.
Hardcoded sandbox: true in layout Script.
Same concern as in pi-provider.tsx - the Pi SDK initialization here also has sandbox: true hardcoded. All three initialization points should use consistent environment-based configuration.
🛠️ Suggested fix
- window.Pi.init({ version: "2.0", sandbox: true });
+ window.Pi.init({ version: "2.0", sandbox: ${process.env.NEXT_PUBLIC_PI_SANDBOX === "true"} });📝 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.
| window.Pi.init({ version: "2.0", sandbox: true }); | |
| window.Pi.init({ version: "2.0", sandbox: ${process.env.NEXT_PUBLIC_PI_SANDBOX === "true"} }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/layout.tsx` at line 38, The Pi SDK init call currently hardcodes sandbox:
true in the window.Pi.init invocation; change it to use the same
environment-based flag used elsewhere (e.g., replace the literal with the shared
env/config variable used in pi-provider.tsx or the global CONFIG/PI_SANDBOX
flag) so all initialization points (window.Pi.init in layout.tsx and the init in
pi-provider.tsx) read from the same runtime environment variable; locate the
window.Pi.init({ version: "2.0", sandbox: true }) call and substitute the
literal with the shared boolean (process.env.NEXT_PUBLIC_PI_SANDBOX or the
existing helper/constant used in the other file) and ensure it's parsed to a
boolean if necessary.
| const handleCopyLink = () => { | ||
| if (rewards?.referralLink) { | ||
| navigator.clipboard.writeText(rewards.referralLink) | ||
| toast({ | ||
| title: "Copied!", | ||
| description: "Referral link copied to clipboard", | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Add error handling for clipboard API.
navigator.clipboard.writeText returns a Promise and can fail (permission denied, non-secure context). Currently, the toast shows "Copied!" even if the operation fails.
🛡️ Proposed fix with error handling
- const handleCopyLink = () => {
+ const handleCopyLink = async () => {
if (rewards?.referralLink) {
- navigator.clipboard.writeText(rewards.referralLink)
- toast({
- title: "Copied!",
- description: "Referral link copied to clipboard",
- })
+ try {
+ await navigator.clipboard.writeText(rewards.referralLink)
+ toast({
+ title: "Copied!",
+ description: "Referral link copied to clipboard",
+ })
+ } catch {
+ toast({
+ title: "Copy failed",
+ description: "Please copy the link manually",
+ variant: "destructive",
+ })
+ }
}
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/profile/rewards/page.tsx` around lines 45 - 53, The handleCopyLink
function calls navigator.clipboard.writeText but doesn't await or handle
failures; update handleCopyLink to await
navigator.clipboard.writeText(rewards.referralLink) and wrap it in try/catch so
the success toast (toast title "Copied!") is only shown on successful
completion, and show an error toast (e.g., title "Copy failed" with a helpful
message) when the promise rejects; keep references to rewards?.referralLink,
navigator.clipboard.writeText, and toast when making this change.
| setIsLoading(true) | ||
| try { | ||
| window.Pi.init({ version: "2.0", }) | ||
| window.Pi.init({ version: "2.0", sandbox: true }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the pi-provider.tsx file
find . -name "pi-provider.tsx" -type fRepository: Pi-Defi-world/Zyradex-frontend
Length of output: 112
🏁 Script executed:
# Check the content around the flagged lines
cat -n components/providers/pi-provider.tsx | sed -n '1,180p'Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 6828
🏁 Script executed:
# Search for other environment variable usages in this file to understand configuration patterns
rg "process\.env|NEXT_PUBLIC" components/providers/pi-provider.tsx -A 2 -B 2Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 56
🏁 Script executed:
# Check if there's a .env file or environment configuration documentation
fd -e ".env*" -e "README*" | head -20Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 56
🏁 Script executed:
# Search for Pi SDK usage patterns across the codebase
rg "Pi\.init|sandbox" --type tsx --type ts | head -30Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 101
🏁 Script executed:
# Check for environment configuration files
find . -maxdepth 2 -type f \( -name ".env*" -o -name "*.config.*" \)Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 112
🏁 Script executed:
# Check environment variable patterns in the codebase
rg "NEXT_PUBLIC|process\.env" --max-count=20 | head -30Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 431
🏁 Script executed:
# Look for Pi SDK documentation or comments about sandbox mode
rg -A5 -B5 "sandbox|Pi\.init" --type ts --type js | head -50Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 2850
🏁 Script executed:
# Check git history for this specific line to understand context
cd components/providers && git log --oneline -p pi-provider.tsx 2>/dev/null | grep -A10 -B10 "sandbox" | head -50 || echo "Git history not available"Repository: Pi-Defi-world/Zyradex-frontend
Length of output: 1508
Hardcoded sandbox: true prevents real Pi transactions in production.
The Pi SDK is initialized with sandbox: true hardcoded in multiple locations (lines 74 and 173 in this file, plus app/layout.tsx). This forces all transactions into test mode, making it impossible for users to perform real Pi transactions in production. The SDK's sandbox parameter is optional and should be configurable based on the environment.
Consider using an environment variable for this setting, consistent with the codebase's existing pattern for configuration (e.g., NEXT_PUBLIC_API_URL):
🛠️ Suggested fix
- window.Pi.init({ version: "2.0", sandbox: true })
+ window.Pi.init({ version: "2.0", sandbox: process.env.NEXT_PUBLIC_PI_SANDBOX === "true" })This issue affects authentication, payment creation, and the main app layout initialization—all three locations should be updated to use the environment variable consistently.
📝 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.
| window.Pi.init({ version: "2.0", sandbox: true }) | |
| window.Pi.init({ version: "2.0", sandbox: process.env.NEXT_PUBLIC_PI_SANDBOX === "true" }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/providers/pi-provider.tsx` at line 74, The Pi SDK is being
initialized with sandbox: true in window.Pi.init (appears in the Pi provider and
the app layout), forcing test-only transactions; change the init calls to read a
public env var (e.g., NEXT_PUBLIC_PI_SANDBOX) and pass a boolean based on its
value instead of the hardcoded true so production can opt out of sandbox mode;
update every place that calls window.Pi.init (the Pi provider initialization and
the layout/init paths referenced in the review) to use the same
environment-driven flag and ensure the value is parsed as a boolean before
passing to sandbox.
|
|
||
| try { | ||
| window.Pi.init({ version: "2.0"}) | ||
| window.Pi.init({ version: "2.0", sandbox: true }) |
There was a problem hiding this comment.
Same sandbox concern applies to createPayment.
This is the same hardcoded sandbox: true issue as in the authenticate function. Both should use the same environment-based configuration for consistency.
🛠️ Suggested fix
- window.Pi.init({ version: "2.0", sandbox: true })
+ window.Pi.init({ version: "2.0", sandbox: process.env.NEXT_PUBLIC_PI_SANDBOX === "true" })📝 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.
| window.Pi.init({ version: "2.0", sandbox: true }) | |
| window.Pi.init({ version: "2.0", sandbox: process.env.NEXT_PUBLIC_PI_SANDBOX === "true" }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/providers/pi-provider.tsx` at line 173, The hardcoded sandbox flag
in window.Pi.init({ version: "2.0", sandbox: true }) should be driven by the
same environment-based configuration used in authenticate/createPayment; replace
the literal true with a shared boolean (e.g., a NEXT_PUBLIC_PI_SANDBOX or
isPiSandbox variable) and wire that into window.Pi.init and into
createPayment/authenticate so both functions use the same env-derived value for
sandbox mode.
| // Capture ref from URL on mount and store for signin | ||
| useEffect(() => { | ||
| if (typeof window === "undefined") return | ||
| const params = new URLSearchParams(window.location.search) | ||
| const ref = params.get("ref") | ||
| if (ref?.trim()) { | ||
| storeReferralRef(ref) | ||
| } | ||
| }, []) |
There was a problem hiding this comment.
Duplicate referral capture - already handled by RefCapture component.
This useEffect duplicates the referral capture logic that RefCapture (rendered in app/layout.tsx) already performs on mount. Both components read ?ref= from the URL and store it in sessionStorage.
Since RefCapture is rendered at the layout level and executes before child components, this hook's capture logic is redundant and could potentially cause a race condition where both write to the same storage key.
🧹 Suggested fix: Remove duplicate capture logic
- // Capture ref from URL on mount and store for signin
- useEffect(() => {
- if (typeof window === "undefined") return
- const params = new URLSearchParams(window.location.search)
- const ref = params.get("ref")
- if (ref?.trim()) {
- storeReferralRef(ref)
- }
- }, [])
-The RefCapture component already handles this, so the hook can focus solely on reading the stored ref during signin.
📝 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.
| // Capture ref from URL on mount and store for signin | |
| useEffect(() => { | |
| if (typeof window === "undefined") return | |
| const params = new URLSearchParams(window.location.search) | |
| const ref = params.get("ref") | |
| if (ref?.trim()) { | |
| storeReferralRef(ref) | |
| } | |
| }, []) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@hooks/useUserProfile.ts` around lines 41 - 49, The useEffect in
useUserProfile.ts that reads URLSearchParams and calls storeReferralRef
duplicates RefCapture (rendered in app/layout.tsx) and should be removed; update
useUserProfile to no longer capture ?ref from window.location in the useEffect
block and instead rely on RefCapture to populate storage, keeping only logic
that reads the stored referral during signin (refer to storeReferralRef and any
signin-related functions in this hook) to avoid double-writes and race
conditions.
Summary by CodeRabbit
New Features
Updates