-
Notifications
You must be signed in to change notification settings - Fork 199
feat: referral dashboard and registering #11377
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: develop
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughThis PR introduces a comprehensive referral system feature, including environment flags, UI components for code management and rewards tracking, hooks for data fetching and URL-based code capture, API integration with the user service, and translations. Additionally, it enhances swapper metadata to include per-swapper-specific fields and order identifiers. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25–35 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ 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 |
| cowswapQuoteSpecific: tradeQuote.steps[0]?.cowswapQuoteResponse, | ||
| portalsTransactionMetadata: tradeQuote.steps[0]?.portalsTransactionMetadata, | ||
| zrxTransactionMetadata: tradeQuote.steps[0]?.zrxTransactionMetadata, | ||
| bebopTransactionMetadata: tradeQuote.steps[0]?.bebopTransactionMetadata, |
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.
Needed to verify upstream that the user did apply the fees
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: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/swapper/src/types.ts (1)
444-459: Critical: Missing type definitions for transaction metadata fields.
SwapperSpecificMetadatais missing three fields that are being assigned insrc/lib/tradeExecution.ts(lines 183-185):
portalsTransactionMetadatazrxTransactionMetadatabebopTransactionMetadataThese fields need to be added to the type definition to match the runtime assignments, or TypeScript compilation will fail.
Apply this diff to add the missing fields:
export type SwapperSpecificMetadata = { chainflipSwapId: number | undefined nearIntentsSpecific?: { depositAddress: string depositMemo?: string timeEstimate: number deadline: string } cowswapQuoteSpecific?: OrderQuoteResponse + portalsTransactionMetadata?: TradeQuoteStep['portalsTransactionMetadata'] + zrxTransactionMetadata?: TradeQuoteStep['zrxTransactionMetadata'] + bebopTransactionMetadata?: TradeQuoteStep['bebopTransactionMetadata'] relayTransactionMetadata: RelayTransactionMetadata | undefined relayerExplorerTxLink: string | undefined relayerTxHash: string | undefined stepIndex: SupportedTradeQuoteStepIndex quoteId: string streamingSwapMetadata: StreamingSwapMetadata | undefined }src/config.ts (1)
12-228: Add Referral flag to test mocksThe config validator and FeatureFlags type are correctly wired, but the test mock in
src/test/mocks/store.tsis missing theReferralentry in thefeatureFlagsobject. AddReferral: false,to the mock (afterAppRatingat line 181) to match the FeatureFlags type definition and prevent test failures.
♻️ Duplicate comments (1)
src/lib/tradeExecution.ts (1)
182-185: Duplicate: Type definitions needed for these metadata fields.These assignments reference the critical issue flagged in
packages/swapper/src/types.tsat lines 444-459. TheportalsTransactionMetadata,zrxTransactionMetadata, andbebopTransactionMetadatafields must be added to theSwapperSpecificMetadatatype definition before these assignments will type-check correctly.
🧹 Nitpick comments (11)
src/components/Referral/index.ts (1)
1-1: Barrel export is OK; just confirm it matches local import conventions. Some parts of the repo prefer direct component-file imports over directory barrels. Based on learnings, consider aligning with the dominant pattern if this causes churn later.src/pages/Fox/FoxEcosystemPage.tsx (1)
11-16: Consider lazy-loadingReferralDashboardbehind the feature flag to avoid bundle impact.import { Box } from '@chakra-ui/react' import { lazy } from 'react' import { useTranslate } from 'react-polyglot' @@ import { Main } from '@/components/Layout/Main' import { SEO } from '@/components/Layout/Seo' -import { ReferralDashboard } from '@/components/Referral' import { useFeatureFlag } from '@/hooks/useFeatureFlag/useFeatureFlag' import { FoxPageProvider } from '@/pages/Fox/hooks/useFoxPageContext' import { makeSuspenseful } from '@/utils/makeSuspenseful' @@ const RFOXSection = makeSuspenseful( lazy(() => import('./components/RFOXSection').then(({ RFOXSection }) => ({ default: RFOXSection })), ), defaultBoxSpinnerStyle, ) + +const ReferralDashboard = makeSuspenseful( + lazy(() => + import('@/components/Referral/ReferralDashboard').then(({ ReferralDashboard }) => ({ + default: ReferralDashboard, + })), + ), + defaultBoxSpinnerStyle, +)This keeps the UI gated while also deferring the module cost until enabled.
Also applies to: 31-43
src/components/Referral/ReferralCodeCard.tsx (1)
43-43: Consider responsive width for mobile.The fixed
width='50%'may not display well on mobile devices. Consider using responsive values.- width='50%' + width={{ base: 'full', md: '50%' }}src/components/Referral/ReferralStatsCards.tsx (2)
5-10: Avoid hardcoding$+ string amounts; prefer a shared fiat formatter component/helper
Right now you’re rendering'$' + (string | fallback)which can drift from the app’s canonical fiat formatting and i18n behavior.- currentRewards?: string - totalRewards?: string + currentRewardsUsd?: string + totalRewardsUsd?: string ... - ${currentRewards ?? '0.00'} + {/* e.g. <Amount.Fiat value={bnOrNumber} /> or Intl.NumberFormat */} + ${currentRewardsUsd ?? '0.00'} ... - ${totalRewards ?? '0.00'} + ${totalRewardsUsd ?? '0.00'}Also applies to: 66-123
20-63: Consider mapping the 3 skeleton cards to reduce duplication
Not blocking, but this is 3x identical markup.- return ( - <> - <Card ...>...</Card> - <Card ...>...</Card> - <Card ...>...</Card> - </> - ) + return ( + <> + {Array.from({ length: 3 }).map((_, i) => ( + <Card + key={i} + flex='1' + minW='200px' + bg='background.surface.raised.base' + borderRadius='xl' + borderTop='1px solid' + borderColor='gray.700' + > + <CardBody textAlign='center' py={6}> + <Skeleton height='40px' width='100px' mx='auto' mb={2} /> + <Skeleton height='20px' width='120px' mx='auto' /> + </CardBody> + </Card> + ))} + </> + )src/components/Referral/ReferralCodesTable.tsx (1)
16-27: Reuse sharedReferralCodetype (orPick) to avoid drift
There’s already aReferralCodeinsrc/lib/referral/types.ts; duplicating it here risks divergence.-import { useTranslate } from 'react-polyglot' +import { useTranslate } from 'react-polyglot' +import type { ReferralCode as ReferralCodeModel } from '@/lib/referral/types' -type ReferralCode = { - code: string - usageCount: number - swapVolumeUsd?: string -} +type ReferralCode = Pick<ReferralCodeModel, 'code' | 'usageCount' | 'swapVolumeUsd'>src/pages/Referral/Referral.tsx (1)
31-39: Avoid duplicatingReferralHeader—reusesrc/components/Referral/ReferralHeader.tsx.
This local component duplicates an existing one (risk of drift). Prefer importing the shared component.src/components/Referral/ReferralCodesManagementTable.tsx (2)
16-29: Type duplication: consider reusingReferralCodefromsrc/lib/referral/types.ts.
ReferralCodeFulloverlaps with the API type; sharing reduces drift (and avoids subtly differentcreatedAtunions across components).
98-103: EnsurecreatedAtis a stable ISO string (or normalize upstream).
new Date(code.createdAt)will behave differently across browsers if the string isn’t ISO-8601. Prefer having the API type becreatedAt: string(ISO) and normalize in one place.src/lib/referral/api.ts (1)
13-28: ConstructReferralApiErrorinstead of castingErrorto it.
This preserves class identity and avoids “fake” typed errors.-import type { +import { CreateReferralCodeRequest, CreateReferralCodeResponse, ReferralApiError, ReferralStats, } from './types' @@ - const apiError = new Error(message) as ReferralApiError - apiError.name = 'ReferralApiError' - apiError.code = code - apiError.statusCode = statusCode - - throw apiError + throw new ReferralApiError(message, code, statusCode)src/lib/referral/types.ts (1)
1-21: Prefer API “wire types” for dates (ISOstring) and normalize once.
HavingDate | stringunions across API/UX layers spreads parsing responsibility; consider makingcreatedAt/expiresAtISOstringin API types and converting at the edge.
| export const CreateCodeCard = ({ | ||
| newCodeInput, | ||
| isCreating, | ||
| onInputChange, | ||
| onGenerateRandom, | ||
| onCreate, | ||
| }: CreateCodeCardProps) => { | ||
| const translate = useTranslate() | ||
|
|
||
| return ( | ||
| <Card | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| py={2} | ||
| > | ||
| <CardHeader> | ||
| <Heading size='md'>{translate('referral.createNewCode')}</Heading> | ||
| </CardHeader> | ||
| <CardBody> | ||
| <HStack> | ||
| <Input | ||
| value={newCodeInput} | ||
| onChange={e => onInputChange(e.target.value.toUpperCase())} | ||
| placeholder={translate('referral.enterCodeOrLeaveEmpty')} | ||
| maxLength={20} | ||
| bg='background.surface.raised.base' | ||
| border='none' | ||
| /> | ||
| <Button | ||
| onClick={onGenerateRandom} | ||
| leftIcon={<FaPlus />} | ||
| variant='outline' | ||
| flexShrink={0} | ||
| borderRadius='full' | ||
| border='1px solid' | ||
| borderColor='gray.700' | ||
| backgroundColor='background.surface.raised.base' | ||
| > | ||
| {translate('referral.random')} | ||
| </Button> | ||
| <Button | ||
| onClick={onCreate} | ||
| colorScheme='blue' | ||
| isLoading={isCreating} | ||
| flexShrink={0} | ||
| borderRadius='full' | ||
| > | ||
| {translate('referral.create')} | ||
| </Button> | ||
| </HStack> |
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.
Sanitize referral-code input to expected charset (avoid create failures on spaces/symbols)
Uppercasing alone still allows invalid characters; this will push avoidable errors into the create mutation.
import { FaPlus } from 'react-icons/fa'
import { useTranslate } from 'react-polyglot'
+const normalizeReferralCodeInput = (value: string): string => {
+ return value.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 20)
+}
+
type CreateCodeCardProps = {
newCodeInput: string
isCreating: boolean
onInputChange: (value: string) => void
@@
<Input
value={newCodeInput}
- onChange={e => onInputChange(e.target.value.toUpperCase())}
+ onChange={e => onInputChange(normalizeReferralCodeInput(e.target.value))}
placeholder={translate('referral.enterCodeOrLeaveEmpty')}
maxLength={20}
bg='background.surface.raised.base'
border='none'
/>🤖 Prompt for AI Agents
In src/components/Referral/CreateCodeCard.tsx around lines 13 to 64, the input
onChange only uppercases the value but still allows spaces and symbols which
cause backend create failures; update the onChange handler to sanitize the value
by removing all characters outside the expected charset (e.g. allow only A–Z and
0–9, optionally dash/underscore if required), strip whitespace and symbols, then
uppercase the result and pass that sanitized string to onInputChange; keep
maxLength and consider also trimming on paste or validating before calling
onCreate so the Create button cannot submit invalid input.
| {translate('referral.yourReferralCode')} | ||
| </Text> | ||
| <Heading size='xl' fontWeight='bold' letterSpacing='wide'> | ||
| {code || 'N/A'} |
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.
Use translation key for fallback text.
The hardcoded 'N/A' should use a translation key for i18n support. As per coding guidelines, all copy/text must use translation keys.
- {code || 'N/A'}
+ {code || translate('common.notAvailable')}Note: You may need to add common.notAvailable to the translations file if it doesn't exist.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/Referral/ReferralCodeCard.tsx around line 54 the fallback text
'N/A' is hardcoded; replace it with the i18n translation key (e.g.
t('common.notAvailable')) and ensure useTranslation is imported and used in the
component (or t is available via props/context). Also add the key
common.notAvailable to the translations JSON for supported locales if it doesn't
exist so the fallback displays correctly.
| <IconButton | ||
| aria-label='Share on X' | ||
| icon={<FaXTwitter />} | ||
| size='md' | ||
| colorScheme='whiteAlpha' | ||
| borderRadius='100%' | ||
| bg='whiteAlpha.200' | ||
| onClick={() => onShareOnX(code)} | ||
| /> | ||
| <IconButton | ||
| aria-label='Copy link' | ||
| icon={<FaCopy />} | ||
| size='md' | ||
| colorScheme='whiteAlpha' | ||
| bg='whiteAlpha.200' | ||
| borderRadius='100%' | ||
| onClick={() => onCopyCode(code)} | ||
| /> |
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.
Use translation keys for aria-labels.
The aria-labels are hardcoded in English, which affects accessibility for non-English users. As per coding guidelines, all text should use translation keys.
<IconButton
- aria-label='Share on X'
+ aria-label={translate('common.shareOnX')}
icon={<FaXTwitter />}
size='md'
colorScheme='whiteAlpha'
borderRadius='100%'
bg='whiteAlpha.200'
onClick={() => onShareOnX(code)}
/>
<IconButton
- aria-label='Copy link'
+ aria-label={translate('common.copy')}
icon={<FaCopy />}📝 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.
| <IconButton | |
| aria-label='Share on X' | |
| icon={<FaXTwitter />} | |
| size='md' | |
| colorScheme='whiteAlpha' | |
| borderRadius='100%' | |
| bg='whiteAlpha.200' | |
| onClick={() => onShareOnX(code)} | |
| /> | |
| <IconButton | |
| aria-label='Copy link' | |
| icon={<FaCopy />} | |
| size='md' | |
| colorScheme='whiteAlpha' | |
| bg='whiteAlpha.200' | |
| borderRadius='100%' | |
| onClick={() => onCopyCode(code)} | |
| /> | |
| <IconButton | |
| aria-label={translate('common.shareOnX')} | |
| icon={<FaXTwitter />} | |
| size='md' | |
| colorScheme='whiteAlpha' | |
| borderRadius='100%' | |
| bg='whiteAlpha.200' | |
| onClick={() => onShareOnX(code)} | |
| /> | |
| <IconButton | |
| aria-label={translate('common.copy')} | |
| icon={<FaCopy />} | |
| size='md' | |
| colorScheme='whiteAlpha' | |
| bg='whiteAlpha.200' | |
| borderRadius='100%' | |
| onClick={() => onCopyCode(code)} | |
| /> |
🤖 Prompt for AI Agents
In src/components/Referral/ReferralCodeCard.tsx around lines 59 to 76 the
aria-label props are hardcoded in English; replace them with translation keys
using your i18n hook (e.g., import and call useTranslation or t) and pass
t('referral.share_on_x') for the Share on X button and t('referral.copy_link')
for the Copy link button (or the exact keys from your locale files), ensuring
the translation hook is imported and used in the component and the aria-label
props receive the translated strings.
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.
Tbh we don't care about aria-labels so meh
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.
@gomesalexandre, understood! I'll skip aria-label suggestions for this codebase going forward.
🧠 Learnings used
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:69-74
Timestamp: 2025-09-10T15:35:36.547Z
Learning: gomesalexandre dismissed alt text accessibility suggestion with "meh" in PR #10458 for EIP155SignTypedDataConfirmation.tsx Image component, consistent with team pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : All copy/text must use translation keys - never hardcode strings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/ShapeShiftMenu.tsx:0-0
Timestamp: 2025-09-16T09:32:14.405Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in ShapeShiftMenu.tsx by referencing his previous comment on NavigationDropdown.tsx where he said "meh keyboard, it's a hover dropdown, how are you going to see it with keyboard nav? sry vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/ShapeShiftMenu.tsx:0-0
Timestamp: 2025-09-16T09:32:14.405Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in ShapeShiftMenu.tsx, referencing his previous comment about hover dropdowns not being suitable for keyboard navigation and apologizing to "vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10187
File: src/assets/translations/en/main.json:205-206
Timestamp: 2025-08-06T08:58:09.096Z
Learning: gomesalexandre considers translation key consolidation (like multiple keys for "view on explorer" functionality) as nice-to-have improvements rather than critical issues. The team doesn't prioritize i18n consistency across the board currently, and they prefer to handle such consolidation suggestions at their own discretion based on other priorities.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/NavigationDropdown.tsx:75-90
Timestamp: 2025-09-16T09:31:15.378Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in NavigationDropdown.tsx, noting that hover dropdowns aren't suitable for keyboard navigation and apologizing to "vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10361
File: src/pages/Markets/components/CardWithSparkline.tsx:83-92
Timestamp: 2025-08-25T23:32:13.876Z
Learning: In shapeshift/web PR #10361, premiumjibles considered the nested button accessibility issue (ChartErrorFallback retry Button inside Card rendered as Button in CardWithSparkline.tsx) out of scope for the error boundaries feature PR, consistent with deferring minor a11y improvements to follow-up PRs.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10272
File: src/components/StarRating/StarRating.tsx:12-0
Timestamp: 2025-08-13T15:52:06.578Z
Learning: In the ShapeShift web codebase, NeOMakinG and the team generally do not prioritize ARIA attributes and accessibility enhancements for interactive components. They prefer to avoid adding accessibility features like role, tabIndex, aria-label, or keyboard handlers to components, even for user-facing interactive elements like star rating systems.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:37-53
Timestamp: 2025-08-22T12:59:01.702Z
Learning: In RewardDistributionActionCard component (src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx), NeOMakinG confirmed that runeAsset is expected to always be defined when the component renders, so defensive guards against undefined runeAsset are not needed.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10191
File: src/pages/Explore/components/CategoryCard.tsx:27-196
Timestamp: 2025-08-06T09:46:50.860Z
Learning: In src/pages/Explore/components/CategoryCard.tsx, NeOMakinG indicated that wrapping the CategoryCard component with React.memo would be "quite useless in this case", suggesting that memoization is not beneficial for this particular component despite it receiving props, likely due to its specific usage patterns or context.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use Chakra UI components and conventions
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
| <IconButton | ||
| aria-label='Share on X' | ||
| icon={<FaXTwitter />} | ||
| size='sm' | ||
| colorScheme='twitter' | ||
| variant='ghost' | ||
| onClick={() => onShareOnX(code.code)} | ||
| /> | ||
| <IconButton | ||
| aria-label='Copy link' | ||
| icon={<FaCopy />} | ||
| size='sm' | ||
| variant='ghost' | ||
| onClick={() => onCopyCode(code.code)} | ||
| /> |
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.
Hardcoded aria-labels should be translated.
Move aria-label='Share on X' / 'Copy link' to translation keys for consistency and localization.
🤖 Prompt for AI Agents
In src/components/Referral/ReferralCodesManagementTable.tsx around lines 106 to
120 the aria-label attributes are hardcoded ("Share on X" and "Copy link");
replace them with translation keys (e.g. t('referral.shareOnX') and
t('referral.copyLink')) using the same i18n hook/translator used in the
component, update the relevant translation JSON files (add referral.shareOnX and
referral.copyLink entries for all supported locales), and ensure the calls pass
the translated string (aria-label={t('referral.shareOnX')}) so labels are
localized and consistent.
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.
ditto don't care about aria labels
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.
@gomesalexandre, understood—I'll skip aria-label translation suggestions going forward.
✏️ Learnings added
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11377
File: src/components/Referral/ReferralCodesManagementTable.tsx:106-120
Timestamp: 2025-12-12T16:18:33.554Z
Learning: gomesalexandre does not require translating aria-label attributes in the shapeshift/web codebase, even though the project guideline states "All copy/text must use translation keys". He considers aria-label localization suggestions unnecessary and prefers to skip them to keep PR scope focused.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10148
File: src/components/MarketTableVirtualized/MarketsTableVirtualized.tsx:88-91
Timestamp: 2025-07-30T20:57:48.176Z
Learning: In src/components/MarketTableVirtualized/MarketsTableVirtualized.tsx, NeOMakinG prefers keeping the hardcoded overscan value (40) over dynamic calculation based on viewport height, prioritizing code simplicity over precision when the current approach works effectively.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : All copy/text must use translation keys - never hardcode strings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:69-74
Timestamp: 2025-09-10T15:35:36.547Z
Learning: gomesalexandre dismissed alt text accessibility suggestion with "meh" in PR #10458 for EIP155SignTypedDataConfirmation.tsx Image component, consistent with team pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10187
File: src/assets/translations/en/main.json:205-206
Timestamp: 2025-08-06T08:58:09.096Z
Learning: gomesalexandre considers translation key consolidation (like multiple keys for "view on explorer" functionality) as nice-to-have improvements rather than critical issues. The team doesn't prioritize i18n consistency across the board currently, and they prefer to handle such consolidation suggestions at their own discretion based on other priorities.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/ShapeShiftMenu.tsx:0-0
Timestamp: 2025-09-16T09:32:14.405Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in ShapeShiftMenu.tsx by referencing his previous comment on NavigationDropdown.tsx where he said "meh keyboard, it's a hover dropdown, how are you going to see it with keyboard nav? sry vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/ShapeShiftMenu.tsx:0-0
Timestamp: 2025-09-16T09:32:14.405Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in ShapeShiftMenu.tsx, referencing his previous comment about hover dropdowns not being suitable for keyboard navigation and apologizing to "vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10361
File: src/pages/Markets/components/CardWithSparkline.tsx:83-92
Timestamp: 2025-08-25T23:32:13.876Z
Learning: In shapeshift/web PR #10361, premiumjibles considered the nested button accessibility issue (ChartErrorFallback retry Button inside Card rendered as Button in CardWithSparkline.tsx) out of scope for the error boundaries feature PR, consistent with deferring minor a11y improvements to follow-up PRs.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/NavigationDropdown.tsx:75-90
Timestamp: 2025-09-16T09:31:15.378Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in NavigationDropdown.tsx, noting that hover dropdowns aren't suitable for keyboard navigation and apologizing to "vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Use Chakra UI components and conventions
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
| ${code.swapVolumeUsd || '0.00'} | ||
| </Box> | ||
| <Box width='120px'> | ||
| <HStack spacing={2} justify='flex-end'> | ||
| <IconButton | ||
| aria-label='Share on X' | ||
| icon={<FaXTwitter />} | ||
| size='sm' | ||
| colorScheme='twitter' | ||
| variant='ghost' | ||
| onClick={() => onShareOnX(code.code)} | ||
| /> | ||
| <IconButton | ||
| aria-label='Copy link' | ||
| icon={<FaCopy />} | ||
| size='sm' | ||
| variant='ghost' | ||
| onClick={() => onCopyCode(code.code)} | ||
| /> |
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.
Translate aria-labels (and consider shared fiat formatting for $ values)
The aria-labels are user-facing strings, and $ is hardcoded.
<IconButton
- aria-label='Share on X'
+ aria-label={translate('referral.shareOnX')}
icon={<FaXTwitter />}
@@
<IconButton
- aria-label='Copy link'
+ aria-label={translate('referral.copyLink')}
icon={<FaCopy />}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/Referral/ReferralCodesTable.tsx around lines 83 to 101, the
aria-label strings are hardcoded and the displayed USD value uses a hardcoded
'$'; update both to use existing i18n and formatting utilities: replace literal
aria-labels with calls to the translation function (e.g. t('referral.shareOnX',
{ code }) and t('referral.copyLink', { code })) so they are localizable and
include the code if needed, and replace the raw "${code.swapVolumeUsd ||
'0.00'}" with the shared currency/fiat formatter (e.g.
formatCurrency(code.swapVolumeUsd, 'USD') or the project's equivalent) so
currency symbol, precision and localization are consistent.
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.
ditto don't care about aria labels
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.
@gomesalexandre Acknowledged, I'll skip aria-label suggestions for this PR. 👍
🧠 Learnings used
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10148
File: src/components/MarketTableVirtualized/MarketsTableVirtualized.tsx:88-91
Timestamp: 2025-07-30T20:57:48.176Z
Learning: In src/components/MarketTableVirtualized/MarketsTableVirtualized.tsx, NeOMakinG prefers keeping the hardcoded overscan value (40) over dynamic calculation based on viewport height, prioritizing code simplicity over precision when the current approach works effectively.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:69-74
Timestamp: 2025-09-10T15:35:36.547Z
Learning: gomesalexandre dismissed alt text accessibility suggestion with "meh" in PR #10458 for EIP155SignTypedDataConfirmation.tsx Image component, consistent with team pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10871
File: src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx:426-428
Timestamp: 2025-10-21T17:11:18.087Z
Learning: In src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx, within the handleInputChange function, use .toFixed() without arguments (not .toString()) when converting BigNumber amounts for input field synchronization. This avoids exponential notation in the input while preserving precision for presentational components like <Amount.Crypto /> and <Amount.Fiat /> to format appropriately.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : All copy/text must use translation keys - never hardcode strings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/StructuredMessage/StructuredMessage.tsx:0-0
Timestamp: 2025-09-13T16:45:17.166Z
Learning: gomesalexandre appreciates safety-focused suggestions for UI rendering in WalletConnect components, specifically defensive programming approaches that prevent null/undefined values from displaying as literal "null"/"undefined" strings in the user interface.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns in WalletConnect modals, including side-effects-during-render for error handling (showErrorToast + handleReject), rather than introducing isolated refactors that would make the codebase inconsistent.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns across WalletConnect modal components, including side-effects-during-render for error handling (showErrorToast + handleReject calls before return null), rather than introducing isolated refactors that would create inconsistency in the codebase.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10280
File: src/context/WalletProvider/MobileWallet/mobileMessageHandlers.ts:18-18
Timestamp: 2025-08-14T12:42:48.263Z
Learning: gomesalexandre prefers maintaining string literal patterns in the Message union type in src/context/WalletProvider/MobileWallet/mobileMessageHandlers.ts, even when there's some duplication between Command union and Message variants. They find properly typed string literals acceptable and prefer not to refactor for type hygiene in this context.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
| export const getReferralStatsByOwner = async ( | ||
| ownerAddress: string, | ||
| startDate?: Date, | ||
| endDate?: Date, | ||
| ): Promise<ReferralStats> => { | ||
| if (!USER_SERVER_URL) { | ||
| throw new Error('User server URL is not configured') | ||
| } | ||
|
|
||
| try { | ||
| const params = new URLSearchParams() | ||
| if (startDate) params.append('startDate', startDate.toISOString()) | ||
| if (endDate) params.append('endDate', endDate.toISOString()) | ||
|
|
||
| const response = await axios.get<ReferralStats>( | ||
| `${USER_SERVER_URL}/referrals/stats/${ownerAddress}${ | ||
| params.toString() ? `?${params.toString()}` : '' | ||
| }`, | ||
| { | ||
| timeout: 10000, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }, | ||
| ) | ||
| return response.data | ||
| } catch (error) { | ||
| return handleApiError(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.
Encode ownerAddress in URL path to avoid malformed requests.
CAIP account IDs include :; other characters could break path parsing.
- const response = await axios.get<ReferralStats>(
- `${USER_SERVER_URL}/referrals/stats/${ownerAddress}${
+ const response = await axios.get<ReferralStats>(
+ `${USER_SERVER_URL}/referrals/stats/${encodeURIComponent(ownerAddress)}${
params.toString() ? `?${params.toString()}` : ''
}`,📝 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 const getReferralStatsByOwner = async ( | |
| ownerAddress: string, | |
| startDate?: Date, | |
| endDate?: Date, | |
| ): Promise<ReferralStats> => { | |
| if (!USER_SERVER_URL) { | |
| throw new Error('User server URL is not configured') | |
| } | |
| try { | |
| const params = new URLSearchParams() | |
| if (startDate) params.append('startDate', startDate.toISOString()) | |
| if (endDate) params.append('endDate', endDate.toISOString()) | |
| const response = await axios.get<ReferralStats>( | |
| `${USER_SERVER_URL}/referrals/stats/${ownerAddress}${ | |
| params.toString() ? `?${params.toString()}` : '' | |
| }`, | |
| { | |
| timeout: 10000, | |
| headers: { 'Content-Type': 'application/json' }, | |
| }, | |
| ) | |
| return response.data | |
| } catch (error) { | |
| return handleApiError(error) | |
| } | |
| } | |
| export const getReferralStatsByOwner = async ( | |
| ownerAddress: string, | |
| startDate?: Date, | |
| endDate?: Date, | |
| ): Promise<ReferralStats> => { | |
| if (!USER_SERVER_URL) { | |
| throw new Error('User server URL is not configured') | |
| } | |
| try { | |
| const params = new URLSearchParams() | |
| if (startDate) params.append('startDate', startDate.toISOString()) | |
| if (endDate) params.append('endDate', endDate.toISOString()) | |
| const response = await axios.get<ReferralStats>( | |
| `${USER_SERVER_URL}/referrals/stats/${encodeURIComponent(ownerAddress)}${ | |
| params.toString() ? `?${params.toString()}` : '' | |
| }`, | |
| { | |
| timeout: 10000, | |
| headers: { 'Content-Type': 'application/json' }, | |
| }, | |
| ) | |
| return response.data | |
| } catch (error) { | |
| return handleApiError(error) | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/lib/referral/api.ts around lines 30 to 57, the ownerAddress is
interpolated directly into the URL path which can produce malformed requests for
CAIP account IDs (they contain ':' and other reserved characters); update the
URL construction to URL-encode the ownerAddress (e.g., via encodeURIComponent)
before inserting it into the path so the request path is safe and reserved
characters don’t break routing, keeping the rest of the query param logic the
same.
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.
owner address is an Address (0x${address} for EVM chains) not an AccountId @coderabbitai
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how ownerAddress is derived in the useReferral hook
echo "=== Checking ownerAddress derivation in useReferral ==="
cat src/hooks/useReferral/useReferral.tsx
echo -e "\n=== Searching for Address type definitions ==="
rg -n "type Address" --type=ts -g '!node_modules' -g '!dist' -C 2
echo -e "\n=== Checking how accountIds are converted to addresses ==="
rg -n "fromAccountId|toAccountId" --type=ts -g '!node_modules' -g '!dist' -C 3
Length of output: 271017
@gomesalexandre good catch — thanks. You’re right: we should be passing an EVM address (0x…) to the referral API, not a CAIP AccountId.
In this PR, useReferral currently uses the first walletEnabledAccountIds entry (a CAIP AccountId). Here’s a focused change to derive the first connected EVM address and use that instead. This also makes the earlier URL-encoding suggestion unnecessary for api.ts.
Diff for src/hooks/useReferral/useReferral.tsx:
@@
-import { skipToken, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
-import { useMemo } from 'react'
+import { skipToken, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
+import { useMemo } from 'react'
+import { fromAccountId } from '@shapeshiftoss/caip'
+import { isEvmChainId } from '@shapeshiftoss/chain-adapters'
+import { getAddress, type Address } from 'viem'
@@
- const walletEnabledAccountIds = useAppSelector(selectWalletEnabledAccountIds)
+ const walletEnabledAccountIds = useAppSelector(selectWalletEnabledAccountIds)
const isWebServicesEnabled = useFeatureFlag('WebServices')
- // Use the first account ID (full CAIP format) as owner identifier
- // Backend will hash it for privacy
- const ownerAddress = useMemo(() => {
- if (walletEnabledAccountIds.length === 0) return null
- return walletEnabledAccountIds[0]
- }, [walletEnabledAccountIds])
+ // Use the first connected EVM address (0x…) as the owner identifier
+ const ownerAddress: Address | null = useMemo(() => {
+ if (walletEnabledAccountIds.length === 0) return null
+ const evmAccountId = walletEnabledAccountIds.find(
+ id => isEvmChainId(fromAccountId(id).chainId),
+ )
+ if (!evmAccountId) return null
+ // Normalize to checksum address
+ return getAddress(fromAccountId(evmAccountId).account)
+ }, [walletEnabledAccountIds])
@@
} = useQuery<ReferralStats, Error>({
queryKey: ['referralStats', ownerAddress, startDate, endDate],
queryFn:
ownerAddress && isWebServicesEnabled
? () => getReferralStatsByOwner(ownerAddress, startDate, endDate)
: skipToken,
})
@@
const { mutateAsync: createCodeMutation, isPending: isCreatingCode } = useMutation({
mutationFn: (request: Omit<CreateReferralCodeRequest, 'ownerAddress'>) => {
- if (!ownerAddress) throw new Error('Wallet not connected')
+ if (!ownerAddress) throw new Error('Wallet not connected')
return createReferralCode({ ...request, ownerAddress })
},Notes:
- No change needed in src/lib/referral/api.ts for path encoding; 0x-prefixed hex addresses are URL-safe.
- Scope is intentionally small: we keep API types as string and ensure the hook reliably supplies an EVM address.
If you prefer, I can also rename the local variable/comment to avoid future confusion (e.g., ownerEvmAddress) — just say the word.
✏️ Learnings added
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11377
File: src/lib/referral/api.ts:30-57
Timestamp: 2025-12-12T16:20:27.769Z
Learning: In shapeshift/web referral feature, the backend expects an EVM address (0x… viem Address) as the owner identifier, not a CAIP AccountId. Update useReferral to derive the first connected EVM address via fromAccountId + getAddress, and do not URL-encode it in the API path.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-125
Timestamp: 2025-11-12T12:49:17.895Z
Learning: In packages/chain-adapters/src/evm/utils.ts, the getErc20Data function already includes a guard that returns an empty string when contractAddress is undefined (line 8: `if (!contractAddress) return ''`). This built-in handling means callers don't need to conditionally invoke getErc20Data—it safely handles both ERC20 tokens and native assets.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
| const handleCreateCode = useCallback(async () => { | ||
| const code = newCodeInput.trim() || generateRandomCode() | ||
|
|
||
| try { | ||
| await createCode({ code }) | ||
| setNewCodeInput('') | ||
| toast({ | ||
| title: translate('referral.codeCreated'), | ||
| description: translate('referral.codeCreatedDescription', { code }), | ||
| status: 'success', | ||
| duration: 3000, | ||
| isClosable: true, | ||
| }) | ||
| } catch (err) { | ||
| toast({ | ||
| title: translate('common.error'), | ||
| description: err instanceof Error ? err.message : translate('referral.createCodeFailed'), | ||
| status: 'error', | ||
| duration: 5000, | ||
| isClosable: true, | ||
| }) | ||
| } | ||
| }, [createCode, newCodeInput, toast, translate]) |
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.
Validate/sanitize referral codes before create/share/copy.
newCodeInput is uppercased but not validated; code is later embedded into URLs and sent to the API. At minimum, restrict to the backend-accepted charset (likely ^[A-Z0-9]+$), enforce length, and show a translated error toast on invalid input.
Also applies to: 387-416
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.
Absolutely valid.
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.
@gomesalexandre Thanks for confirming! For the validation, a regex like /^[A-Z0-9]+$/ would work well for uppercase alphanumeric codes. Best practice suggests using patterns like ^[a-zA-Z0-9]*$ for alphanumeric referral codes, and avoiding confusable characters like O's, zeros, ones, capital I's, or lowercase L's.
You might also want to enforce length constraints (e.g., 3-20 chars) to match what the backend expects. A simple check before calling createCode would prevent invalid inputs from reaching the API and provide better UX with immediate feedback.
🧠 Learnings used
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/StructuredMessage/StructuredMessage.tsx:0-0
Timestamp: 2025-09-13T16:45:17.166Z
Learning: gomesalexandre appreciates safety-focused suggestions for UI rendering in WalletConnect components, specifically defensive programming approaches that prevent null/undefined values from displaying as literal "null"/"undefined" strings in the user interface.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10643
File: src/lib/address/bip21.ts:33-40
Timestamp: 2025-09-25T20:52:54.121Z
Learning: gomesalexandre prefers strict adherence to URL scheme standards in ERC-681 parsing rather than defensive case-insensitive handling. He believes schemes should always be lowercase per standard, and if they're uppercase "it's the fault of whoever generated that" - preferring to let malformed URLs fail rather than accommodate non-standard formatting.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns in WalletConnect modals, including side-effects-during-render for error handling (showErrorToast + handleReject), rather than introducing isolated refactors that would make the codebase inconsistent.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:0-0
Timestamp: 2025-09-12T11:56:19.437Z
Learning: gomesalexandre rejected verbose try/catch error handling for address validation in Tenderly integration (PR #10461), calling the approach "ugly" but still implemented safety measures in commit ad7e424b89, preferring cleaner safety implementations over defensive programming patterns.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns across WalletConnect modal components, including side-effects-during-render for error handling (showErrorToast + handleReject calls before return null), rather than introducing isolated refactors that would create inconsistency in the codebase.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:0-0
Timestamp: 2025-09-12T13:26:26.277Z
Learning: gomesalexandre uses "we do that errwhere ser" (everywhere, sir) to indicate that client-side API key exposure is an accepted codebase-wide pattern, consistent with his comfort level for development/preparatory phases across the WalletConnect/Tenderly integration.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Validate all inputs, especially user inputs
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10643
File: src/lib/address/bip21.ts:52-60
Timestamp: 2025-09-25T20:53:08.418Z
Learning: gomesalexandre prefers not to add case-insensitive URL scheme handling, as URL schemes are canonically lowercase per RFC standards and if they're uppercase, it's the fault of the URL generator, not something the parsing code should accommodate.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
| const handleShareOnX = useCallback((code: string) => { | ||
| const shareUrl = `${window.location.origin}/#/?ref=${code}` | ||
| const text = `Join me on ShapeShift using my referral code ${code}!` | ||
| const twitterUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent( | ||
| text, | ||
| )}&url=${encodeURIComponent(shareUrl)}` | ||
| window.open(twitterUrl, '_blank', 'noopener,noreferrer') | ||
| }, []) | ||
|
|
||
| const handleCopyCode = useCallback( | ||
| (code: string) => { | ||
| const shareUrl = `${window.location.origin}/#/?ref=${code}` | ||
| navigator.clipboard.writeText(shareUrl) | ||
| toast({ | ||
| title: translate('common.copied'), | ||
| status: 'success', | ||
| duration: 2000, | ||
| }) | ||
| }, | ||
| [toast, translate], | ||
| ) |
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.
Hardcoded user-facing strings (incl. aria-labels) violate i18n/a11y conventions.
Move "N/A", "Coming Soon", "Join me on ShapeShift...", and all aria-label strings to translation keys.
Also applies to: 142-152, 158-175, 294-299
🤖 Prompt for AI Agents
In src/pages/Referral/Referral.tsx around lines 94-114 (and also apply same
changes at 142-152, 158-175, 294-299): several user-facing strings are hardcoded
(e.g. "Join me on ShapeShift using my referral code ...", toast title "Copied",
plus multiple aria-label values and labels like "N/A" and "Coming Soon");
replace those literals with translation keys via the existing translate(...)
function (e.g. create keys like referral.shareText, referral.copied,
referral.na, referral.comingSoon and aria labels referral.copyAria,
referral.shareAria, etc.), use translate(...) to build the share text before
encodeURIComponent, use translate(...) for toast.title, and replace all
aria-label props with translate(...) calls; ensure the new i18n keys are added
to the translation files and update any unit/component tests to expect
translated strings.
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.
Valid too but disregard (incl. aria-labels) - fine to also add since it's just one prompt, but irrelevant
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.
@gomesalexandre Understood, I'll disregard the i18n suggestion for this PR. Thanks for clarifying! 👍
🧠 Learnings used
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10760
File: src/components/ManageHiddenAssets/ManageHiddenAssetsList.tsx:78-84
Timestamp: 2025-10-07T03:44:27.350Z
Learning: In the ShapeShift web codebase, the following are stable references and do not need to be included in useCallback/useMemo dependency arrays:
- `navigate` from `useBrowserRouter()` hook
- Modal control objects (like `walletDrawer`) from `useModal()` hook (including their `isOpen`, `close`, and `open` methods)
- These are backed by stable context providers
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10139
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx:109-115
Timestamp: 2025-07-29T15:04:28.083Z
Learning: In src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx, the component is used under an umbrella that 100% of the time contains the quote, making the type assertion `activeTradeQuote?.steps[currentHopIndex] as TradeQuoteStep` safe. Adding conditional returns before hooks would violate React's Rules of Hooks.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : All copy/text must use translation keys - never hardcode strings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:69-74
Timestamp: 2025-09-10T15:35:36.547Z
Learning: gomesalexandre dismissed alt text accessibility suggestion with "meh" in PR #10458 for EIP155SignTypedDataConfirmation.tsx Image component, consistent with team pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10272
File: src/components/RatingModal.tsx:104-0
Timestamp: 2025-08-13T15:50:41.994Z
Learning: In the ShapeShift web codebase, internal strings like Discord webhook embed content (used for team notifications/feedback) don't need to be translated, only user-facing strings require translation keys. The team distinguishes between internal tooling strings and user-facing UI strings for internationalization purposes.
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10361
File: src/pages/Markets/components/CardWithSparkline.tsx:83-92
Timestamp: 2025-08-25T23:32:13.876Z
Learning: In shapeshift/web PR #10361, premiumjibles considered the nested button accessibility issue (ChartErrorFallback retry Button inside Card rendered as Button in CardWithSparkline.tsx) out of scope for the error boundaries feature PR, consistent with deferring minor a11y improvements to follow-up PRs.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/ShapeShiftMenu.tsx:0-0
Timestamp: 2025-09-16T09:32:14.405Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in ShapeShiftMenu.tsx by referencing his previous comment on NavigationDropdown.tsx where he said "meh keyboard, it's a hover dropdown, how are you going to see it with keyboard nav? sry vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10490
File: src/components/Layout/Header/NavBar/ShapeShiftMenu.tsx:0-0
Timestamp: 2025-09-16T09:32:14.405Z
Learning: gomesalexandre dismissed keyboard accessibility suggestion for hover dropdown in ShapeShiftMenu.tsx, referencing his previous comment about hover dropdowns not being suitable for keyboard navigation and apologizing to "vimium users", consistent with his pattern of deferring minor a11y improvements to keep PR scope focused.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10272
File: src/components/RatingModal.tsx:34-0
Timestamp: 2025-08-13T15:50:02.727Z
Learning: In the ShapeShift web codebase, internal strings that are used internally by the English-speaking team don't need to be internationalized, even when other user-facing strings in the same component are translated.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
| <Stack spacing={8}> | ||
| <Flex gap={4} flexWrap='wrap'> | ||
| <Card | ||
| color='white' | ||
| borderRadius='2xl' | ||
| overflow='hidden' | ||
| width='50%' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody px={6} py={4} display='flex' alignItems='center'> | ||
| <Flex alignItems='center' justifyContent='space-between' width='full'> | ||
| <Flex flexDirection='column' gap={0}> | ||
| <Text fontSize='md' opacity={0.7} mb={1}> | ||
| {translate('referral.yourReferralCode')} | ||
| </Text> | ||
| <Heading size='xl' fontWeight='bold' letterSpacing='wide'> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='120px' /> | ||
| ) : defaultCode ? ( | ||
| defaultCode.code | ||
| ) : ( | ||
| 'N/A' | ||
| )} | ||
| </Heading> | ||
| </Flex> | ||
| {defaultCode && ( | ||
| <Flex alignItems='center' gap={2}> | ||
| <IconButton | ||
| aria-label='Share on X' | ||
| icon={<FaXTwitter />} | ||
| size='md' | ||
| colorScheme='whiteAlpha' | ||
| borderRadius='100%' | ||
| bg='whiteAlpha.200' | ||
| onClick={() => handleShareOnX(defaultCode.code)} | ||
| /> | ||
| <IconButton | ||
| aria-label='Copy link' | ||
| icon={<FaCopy />} | ||
| size='md' | ||
| colorScheme='whiteAlpha' | ||
| bg='whiteAlpha.200' | ||
| borderRadius='100%' | ||
| onClick={() => handleCopyCode(defaultCode.code)} | ||
| /> | ||
| </Flex> | ||
| )} | ||
| </Flex> | ||
| </CardBody> | ||
| </Card> | ||
|
|
||
| <Card | ||
| flex='1' | ||
| minW='200px' | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody textAlign='center' py={6}> | ||
| <Heading size='lg' fontWeight='bold' mb={2}> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='100px' mx='auto' /> | ||
| ) : ( | ||
| `$${referralStats?.totalReferrerCommissionUsd ?? '0.00'}` | ||
| )} | ||
| </Heading> | ||
| <Text fontSize='md' color='text.subtle'> | ||
| {translate('referral.currentRewards')} | ||
| </Text> | ||
| </CardBody> | ||
| </Card> | ||
|
|
||
| <Card | ||
| flex='1' | ||
| minW='200px' | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody textAlign='center' py={6}> | ||
| <Heading size='lg' fontWeight='bold' mb={2}> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='100px' mx='auto' /> | ||
| ) : ( | ||
| `$${referralStats?.totalFeesCollectedUsd ?? '0.00'}` | ||
| )} | ||
| </Heading> | ||
| <Text fontSize='md' color='text.subtle'> | ||
| {translate('referral.totalRewards')} | ||
| </Text> | ||
| </CardBody> | ||
| </Card> | ||
|
|
||
| <Card | ||
| flex='1' | ||
| minW='200px' | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody textAlign='center' py={6}> | ||
| <HStack spacing={2} justify='center' mb={2}> | ||
| <Icon as={FaUser} boxSize={5} color='text.subtle' /> | ||
| <Heading size='lg' fontWeight='bold'> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='60px' /> | ||
| ) : ( | ||
| referralStats?.totalReferrals ?? 0 | ||
| )} | ||
| </Heading> | ||
| </HStack> | ||
| <Text fontSize='md' color='text.subtle'> | ||
| {translate('referral.totalReferred')} | ||
| </Text> | ||
| </CardBody> | ||
| </Card> | ||
| </Flex> |
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.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the file to understand the full context of lines 129-249 and 303-507
wc -l src/pages/Referral/Referral.tsxRepository: shapeshift/web
Length of output: 93
🏁 Script executed:
# Read the relevant sections to understand the layout structure
sed -n '129,249p' src/pages/Referral/Referral.tsxRepository: shapeshift/web
Length of output: 4444
🏁 Script executed:
# Also check the second range mentioned
sed -n '303,507p' src/pages/Referral/Referral.tsxRepository: shapeshift/web
Length of output: 8698
🏁 Script executed:
# Let's check if there are any responsive design patterns used elsewhere in the Referral component
grep -n "width={{" src/pages/Referral/Referral.tsx | head -20Repository: shapeshift/web
Length of output: 40
🏁 Script executed:
# Check if there are other Chakra Flex/Box components with responsive props to understand codebase patterns
grep -n "base.*md\|base.*sm\|base.*lg" src/pages/Referral/Referral.tsx | head -10Repository: shapeshift/web
Length of output: 40
🏁 Script executed:
# Check similar card-based layouts in the codebase for responsive patterns
fd -e tsx -e ts . src/pages --maxdepth 2 | head -5 | xargs -I {} bash -c "grep -l 'flexWrap.*wrap\|width.*50%' {} 2>/dev/null" | head -3Repository: shapeshift/web
Length of output: 40
🏁 Script executed:
# Let's examine the beginning of the file to understand component structure and see if there's any Chakra theme or responsive context
head -50 src/pages/Referral/Referral.tsxRepository: shapeshift/web
Length of output: 1172
Add responsive breakpoints to prevent mobile horizontal scroll.
The layout uses fixed widths that will overflow on mobile: width='50%' on line 137 and multiple fixed column widths (150px, 120px, 100px) in the table sections (lines 303-507). Use Chakra responsive props like width={{ base: '100%', md: '50%' }} and stack fixed columns as a single responsive column on small breakpoints to ensure proper display on 320px viewports without horizontal scroll.
🤖 Prompt for AI Agents
In src/pages/Referral/Referral.tsx around lines 129-249 (and also address fixed
column widths in the table area around lines 303-507), the layout uses fixed
widths that cause horizontal overflow on small screens; change the hard-coded
sizes to Chakra responsive props and make columns stack on small breakpoints.
Replace width='50%' with a responsive prop (e.g. base 100% and md 50%), convert
minW/fixed pixel widths on cards and Icon/Skeleton widths to responsive values
or remove fixed px sizes, ensure Card flexes (flex='1') and use responsive minW
or wrap behavior (stack into a single column at base) so elements do not
overflow at 320px, and update table column definitions to collapse/stack into a
single column or use responsive display (e.g. hide less-critical columns on base
or enable internal horizontal scrolling only for wide tables).
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.
Sounds sane - good reminder to test this on mobile viewports too
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.
@gomesalexandre Thanks! Mobile testing will definitely help catch any overflow issues on smaller viewports. Let me know if you'd like me to review the responsive changes once they're in place. 👍
🧠 Learnings used
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx:26-29
Timestamp: 2025-08-22T12:59:01.210Z
Learning: In src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx, NeOMakinG declined wrapping the RewardDistributionActionCard component with React.memo, saying it was "too much", suggesting that like other action center components, memoization is not beneficial for this specific use case.
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10760
File: src/components/ManageHiddenAssets/ManageHiddenAssetsList.tsx:78-84
Timestamp: 2025-10-07T03:44:27.350Z
Learning: In the ShapeShift web codebase, the following are stable references and do not need to be included in useCallback/useMemo dependency arrays:
- `navigate` from `useBrowserRouter()` hook
- Modal control objects (like `walletDrawer`) from `useModal()` hook (including their `isOpen`, `close`, and `open` methods)
- These are backed by stable context providers
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Account for responsive mobile designs in all UI components
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/react-best-practices.mdc:0-0
Timestamp: 2025-11-24T21:20:44.637Z
Learning: Applies to **/*.{jsx,tsx} : KEEP component files under 200 lines when possible; BREAK DOWN large components into smaller, reusable pieces
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10430
File: src/components/Layout/Header/NavBar/PopoverWallet.tsx:72-94
Timestamp: 2025-09-04T12:16:47.748Z
Learning: gomesalexandre declined to add error boundaries to the PopoverWallet component in src/components/Layout/Header/NavBar/PopoverWallet.tsx, stating he didn't touch this component and preferring not to expand the scope of the PR with error boundary additions.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/StructuredMessage/StructuredMessage.tsx:0-0
Timestamp: 2025-09-13T16:45:17.166Z
Learning: gomesalexandre appreciates safety-focused suggestions for UI rendering in WalletConnect components, specifically defensive programming approaches that prevent null/undefined values from displaying as literal "null"/"undefined" strings in the user interface.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:69-74
Timestamp: 2025-09-10T15:35:36.547Z
Learning: gomesalexandre dismissed alt text accessibility suggestion with "meh" in PR #10458 for EIP155SignTypedDataConfirmation.tsx Image component, consistent with team pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/pages/Explore/ExploreCategory.tsx:231-238
Timestamp: 2025-08-08T14:59:40.422Z
Learning: In src/pages/Explore/ExploreCategory.tsx, for the PageHeader filter trigger, NeOMakinG considers changing a clickable Chakra Icon to IconButton too nitpicky for this PR and prefers to keep the current Icon-based trigger; such minor a11y/UI nitpicks should be deferred to a follow-up if needed.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10148
File: src/components/MarketTableVirtualized/MarketsTableVirtualized.tsx:88-91
Timestamp: 2025-07-30T20:57:48.176Z
Learning: In src/components/MarketTableVirtualized/MarketsTableVirtualized.tsx, NeOMakinG prefers keeping the hardcoded overscan value (40) over dynamic calculation based on viewport height, prioritizing code simplicity over precision when the current approach works effectively.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.
| WebServices: boolean | ||
| AddressBook: boolean | ||
| AppRating: boolean | ||
| Referral: boolean |
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.
🧩 Analysis chain
🏁 Script executed:
rg -n 'Referral' src/test/mocks/store.ts -A 2 -B 2Repository: shapeshift/web
Length of output: 40
🏁 Script executed:
cat -n src/state/slices/preferencesSlice/preferencesSlice.ts | sed -n '100,120p'Repository: shapeshift/web
Length of output: 838
🏁 Script executed:
cat -n src/state/slices/preferencesSlice/preferencesSlice.ts | sed -n '240,260p'Repository: shapeshift/web
Length of output: 1189
Add Referral flag to test mock at src/test/mocks/store.ts.
The type definition and initial state in preferencesSlice.ts are correctly implemented. However, the Referral feature flag is missing from the test mock, which will cause test failures. This flag must be added to the mock's feature flags object following the existing pattern.
🤖 Prompt for AI Agents
In src/state/slices/preferencesSlice/preferencesSlice.ts around line 109, the
Preferences type includes a Referral: boolean flag but the test mock at
src/test/mocks/store.ts is missing this feature flag; update the mock's feature
flags object to include Referral with the same boolean default-pattern used by
other flags (add the key "Referral" and set it to true or false consistent with
existing mock values) so tests reflect the slice's type and initial state.
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.
Eyy nice catch Mr Robot.
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.
Rate Limit Exceeded
@gomesalexandre have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 17 seconds before sending another message.
gomesalexandre
left a comment
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.
Very first pass, few major bits but for the most part nothing major spotted.
Will review at runtime on Monday once Mr Rabbit/self comments are tackled (commits or closed) and CI is happy
| estimatedExecutionTimeMs: isCrossChain ? 300000 : 0, | ||
| portalsTransactionMetadata: { | ||
| ...tx, | ||
| orderId: portalsTradeOrderResponse.context.orderId, |
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.
👀
| } | ||
|
|
||
| type ReferralCodesManagementTableProps = { | ||
| codes: ReferralCodeFull[] |
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.
suggestion: referralCode vernacular across the board - just a quick prompt to align that and we're gucci
| import { useReferral } from '@/hooks/useReferral/useReferral' | ||
|
|
||
| const generateRandomCode = () => { | ||
| const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' |
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.
add TODO to make this actually nice and random and ask Coderabbit to create an issue? Also this should probably be generated server-side?
| WebServices: getConfig().VITE_FEATURE_NOTIFICATIONS_WEBSERVICES, | ||
| AddressBook: getConfig().VITE_FEATURE_ADDRESS_BOOK, | ||
| AppRating: getConfig().VITE_FEATURE_APP_RATING, | ||
| Referral: getConfig().VITE_FEATURE_REFERRAL, |
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.
Add to mocks too or CI will be v. sad
| type ReferralCode = { | ||
| code: string | ||
| usageCount: number | ||
| swapVolumeUsd?: string | ||
| } |
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.
preferably-blocking: leverage ReferralCode exported type since this is a subset of it (can either ensure we comply to it or use a Partial if we really don't, or just improve the exported type with more optionals)
| export const getReferralStatsByOwner = async ( | ||
| ownerAddress: string, | ||
| startDate?: Date, | ||
| endDate?: Date, | ||
| ): Promise<ReferralStats> => { | ||
| if (!USER_SERVER_URL) { | ||
| throw new Error('User server URL is not configured') | ||
| } | ||
|
|
||
| try { | ||
| const params = new URLSearchParams() | ||
| if (startDate) params.append('startDate', startDate.toISOString()) | ||
| if (endDate) params.append('endDate', endDate.toISOString()) | ||
|
|
||
| const response = await axios.get<ReferralStats>( | ||
| `${USER_SERVER_URL}/referrals/stats/${ownerAddress}${ | ||
| params.toString() ? `?${params.toString()}` : '' | ||
| }`, | ||
| { | ||
| timeout: 10000, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| }, | ||
| ) | ||
| return response.data | ||
| } catch (error) { | ||
| return handleApiError(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.
owner address is an Address (0x${address} for EVM chains) not an AccountId @coderabbitai
| const handleCreateCode = useCallback(async () => { | ||
| const code = newCodeInput.trim() || generateRandomCode() | ||
|
|
||
| try { | ||
| await createCode({ code }) | ||
| setNewCodeInput('') | ||
| toast({ | ||
| title: translate('referral.codeCreated'), | ||
| description: translate('referral.codeCreatedDescription', { code }), | ||
| status: 'success', | ||
| duration: 3000, | ||
| isClosable: true, | ||
| }) | ||
| } catch (err) { | ||
| toast({ | ||
| title: translate('common.error'), | ||
| description: err instanceof Error ? err.message : translate('referral.createCodeFailed'), | ||
| status: 'error', | ||
| duration: 5000, | ||
| isClosable: true, | ||
| }) | ||
| } | ||
| }, [createCode, newCodeInput, toast, translate]) |
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.
Absolutely valid.
| const handleShareOnX = useCallback((code: string) => { | ||
| const shareUrl = `${window.location.origin}/#/?ref=${code}` | ||
| const text = `Join me on ShapeShift using my referral code ${code}!` | ||
| const twitterUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent( | ||
| text, | ||
| )}&url=${encodeURIComponent(shareUrl)}` | ||
| window.open(twitterUrl, '_blank', 'noopener,noreferrer') | ||
| }, []) | ||
|
|
||
| const handleCopyCode = useCallback( | ||
| (code: string) => { | ||
| const shareUrl = `${window.location.origin}/#/?ref=${code}` | ||
| navigator.clipboard.writeText(shareUrl) | ||
| toast({ | ||
| title: translate('common.copied'), | ||
| status: 'success', | ||
| duration: 2000, | ||
| }) | ||
| }, | ||
| [toast, translate], | ||
| ) |
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.
Valid too but disregard (incl. aria-labels) - fine to also add since it's just one prompt, but irrelevant
| <Stack spacing={8}> | ||
| <Flex gap={4} flexWrap='wrap'> | ||
| <Card | ||
| color='white' | ||
| borderRadius='2xl' | ||
| overflow='hidden' | ||
| width='50%' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody px={6} py={4} display='flex' alignItems='center'> | ||
| <Flex alignItems='center' justifyContent='space-between' width='full'> | ||
| <Flex flexDirection='column' gap={0}> | ||
| <Text fontSize='md' opacity={0.7} mb={1}> | ||
| {translate('referral.yourReferralCode')} | ||
| </Text> | ||
| <Heading size='xl' fontWeight='bold' letterSpacing='wide'> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='120px' /> | ||
| ) : defaultCode ? ( | ||
| defaultCode.code | ||
| ) : ( | ||
| 'N/A' | ||
| )} | ||
| </Heading> | ||
| </Flex> | ||
| {defaultCode && ( | ||
| <Flex alignItems='center' gap={2}> | ||
| <IconButton | ||
| aria-label='Share on X' | ||
| icon={<FaXTwitter />} | ||
| size='md' | ||
| colorScheme='whiteAlpha' | ||
| borderRadius='100%' | ||
| bg='whiteAlpha.200' | ||
| onClick={() => handleShareOnX(defaultCode.code)} | ||
| /> | ||
| <IconButton | ||
| aria-label='Copy link' | ||
| icon={<FaCopy />} | ||
| size='md' | ||
| colorScheme='whiteAlpha' | ||
| bg='whiteAlpha.200' | ||
| borderRadius='100%' | ||
| onClick={() => handleCopyCode(defaultCode.code)} | ||
| /> | ||
| </Flex> | ||
| )} | ||
| </Flex> | ||
| </CardBody> | ||
| </Card> | ||
|
|
||
| <Card | ||
| flex='1' | ||
| minW='200px' | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody textAlign='center' py={6}> | ||
| <Heading size='lg' fontWeight='bold' mb={2}> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='100px' mx='auto' /> | ||
| ) : ( | ||
| `$${referralStats?.totalReferrerCommissionUsd ?? '0.00'}` | ||
| )} | ||
| </Heading> | ||
| <Text fontSize='md' color='text.subtle'> | ||
| {translate('referral.currentRewards')} | ||
| </Text> | ||
| </CardBody> | ||
| </Card> | ||
|
|
||
| <Card | ||
| flex='1' | ||
| minW='200px' | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody textAlign='center' py={6}> | ||
| <Heading size='lg' fontWeight='bold' mb={2}> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='100px' mx='auto' /> | ||
| ) : ( | ||
| `$${referralStats?.totalFeesCollectedUsd ?? '0.00'}` | ||
| )} | ||
| </Heading> | ||
| <Text fontSize='md' color='text.subtle'> | ||
| {translate('referral.totalRewards')} | ||
| </Text> | ||
| </CardBody> | ||
| </Card> | ||
|
|
||
| <Card | ||
| flex='1' | ||
| minW='200px' | ||
| bg='background.surface.raised.base' | ||
| borderRadius='xl' | ||
| borderTop='1px solid' | ||
| borderColor='gray.700' | ||
| > | ||
| <CardBody textAlign='center' py={6}> | ||
| <HStack spacing={2} justify='center' mb={2}> | ||
| <Icon as={FaUser} boxSize={5} color='text.subtle' /> | ||
| <Heading size='lg' fontWeight='bold'> | ||
| {isLoadingReferralStats ? ( | ||
| <Skeleton height='40px' width='60px' /> | ||
| ) : ( | ||
| referralStats?.totalReferrals ?? 0 | ||
| )} | ||
| </Heading> | ||
| </HStack> | ||
| <Text fontSize='md' color='text.subtle'> | ||
| {translate('referral.totalReferred')} | ||
| </Text> | ||
| </CardBody> | ||
| </Card> | ||
| </Flex> |
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.
Sounds sane - good reminder to test this on mobile viewports too
| WebServices: boolean | ||
| AddressBook: boolean | ||
| AppRating: boolean | ||
| Referral: boolean |
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.
Eyy nice catch Mr Robot.
|
Switching to draft until we know how we will distribute amount, focusing on other priorities |
Description
Implement the referral dashboard:
Issue (if applicable)
No issue
Risk
Low, under a flag and not activated yet
Testing
Engineering
Operations
Screenshots (if applicable)
Summary by CodeRabbit
New Features
Bug Fixes
Navigation
✏️ Tip: You can customize this high-level summary in your review settings.