feat: market page detail + campaigns#297
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@antoncoding has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 50 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughExtends chart timeframes to 3M/6M, refactors market header to an animated expandable panel, enriches Merkl campaign data with name/opportunityIdentifier and updates campaign-modal UI (filtering, simplified rows, URL identifier logic). Changes
Sequence Diagram(s)(omitted — changes are UI/formatting and incremental timeline additions that do not introduce a new multi-component sequential flow requiring visualization) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @src/hooks/useMarketCampaigns.ts:
- Around line 45-46: Remove the debug console.log call that prints
singleTokenCampaigns in useMarketCampaigns.ts: delete the line containing
console.log('singleTokenCampaigns', singleTokenCampaigns) (or guard it behind a
dev-only check) so production consoles are not polluted; locate it inside the
hook function where the singleTokenCampaigns variable is computed and remove or
replace it with proper logging if needed.
🧹 Nitpick comments (2)
src/stores/useMarketDetailChartState.ts (1)
37-43: Consider extracting the timeframe union type.The
'1d' | '7d' | '30d' | '3m' | '6m'union is repeated 4 times in this file. Extract to a named type for maintainability.Suggested change
+export type ChartTimeframe = '1d' | '7d' | '30d' | '3m' | '6m'; + // Helper to calculate time range based on timeframe string -const calculateTimeRange = (timeframe: '1d' | '7d' | '30d' | '3m' | '6m'): TimeseriesOptions => { +const calculateTimeRange = (timeframe: ChartTimeframe): TimeseriesOptions => {Then use
ChartTimeframein the type definitions and function signatures.src/features/market-detail/components/campaign-modal.tsx (1)
109-110: Consider memoizing the filter.If
campaignsarray is large, filtering on every render may be wasteful. Wrap inuseMemowithcampaignsdependency.Suggested change
+import { useMemo } from 'react'; + export function CampaignModal({ isOpen, onClose, campaigns }: CampaignModalProps) { + // Filter out blacklisted campaigns + const filteredCampaigns = useMemo( + () => campaigns.filter((c) => !BLACKLISTED_CAMPAIGN_IDS.includes(c.campaignId)), + [campaigns] + ); + if (!isOpen) return null; - - // Filter out blacklisted campaigns - const filteredCampaigns = campaigns.filter((c) => !BLACKLISTED_CAMPAIGN_IDS.includes(c.campaignId));
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/features/market-detail/components/campaign-modal.tsxsrc/features/market-detail/components/charts/chart-utils.tsxsrc/features/market-detail/components/charts/rate-chart.tsxsrc/features/market-detail/components/charts/volume-chart.tsxsrc/features/market-detail/components/market-header.tsxsrc/hooks/useMarketCampaigns.tssrc/stores/useMarketDetailChartState.tssrc/utils/merklApi.tssrc/utils/merklTypes.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-09T10:06:39.848Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:39.848Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. In your code under src/hooks, use: const { address, chainId, isConnected } = useConnection() from 'wagmi' to access the connected wallet information.
Applied to files:
src/hooks/useMarketCampaigns.ts
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 63
File: app/markets/components/MarketRowDetail.tsx:49-52
Timestamp: 2024-10-12T09:23:16.495Z
Learning: When rendering oracle feeds in `ExpandedMarketDetail` (`app/markets/components/MarketRowDetail.tsx`), prefer explicit rendering over iterating keys when dealing with a small number of feeds.
Applied to files:
src/features/market-detail/components/market-header.tsx
📚 Learning: 2025-11-13T20:32:48.908Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 183
File: app/positions/components/RebalanceModal.tsx:301-308
Timestamp: 2025-11-13T20:32:48.908Z
Learning: The TokenIcon component in the codebase accepts a `symbol` prop as part of its valid interface, in addition to `address`, `chainId`, `width`, `height`, and other props.
Applied to files:
src/features/market-detail/components/market-header.tsx
🧬 Code graph analysis (6)
src/features/market-detail/components/charts/volume-chart.tsx (1)
src/components/ui/select.tsx (1)
SelectItem(136-136)
src/features/market-detail/components/market-header.tsx (4)
src/components/shared/token-icon.tsx (1)
TokenIcon(23-95)src/components/shared/address-identity.tsx (1)
AddressIdentity(20-49)src/utils/morpho.ts (1)
getIRMTitle(51-70)src/features/markets/components/oracle/MarketOracle/OracleTypeInfo.tsx (1)
OracleTypeInfo(18-70)
src/features/market-detail/components/charts/rate-chart.tsx (1)
src/components/ui/select.tsx (1)
SelectItem(136-136)
src/utils/merklApi.ts (1)
src/utils/merklTypes.ts (1)
SimplifiedCampaign(133-159)
src/features/market-detail/components/campaign-modal.tsx (2)
src/utils/merklTypes.ts (1)
SimplifiedCampaign(133-159)src/utils/external.ts (1)
getMerklCampaignURL(57-60)
src/stores/useMarketDetailChartState.ts (1)
src/utils/types.ts (1)
TimeseriesOptions(341-345)
🔇 Additional comments (17)
src/stores/useMarketDetailChartState.ts (2)
6-6: LGTM on the constant.Using 30 days as a month approximation is fine for chart purposes.
9-34: Timeframe logic looks correct.The '3m' and '6m' cases are handled consistently with 'DAY' intervals which makes sense for longer ranges.
src/utils/merklTypes.ts (1)
157-158: LGTM.Optional field addition is backward compatible.
src/features/market-detail/components/charts/rate-chart.tsx (1)
47-49: LGTM.Timeframe extension is consistent with the store and other chart components.
Also applies to: 127-127, 136-137
src/features/market-detail/components/charts/chart-utils.tsx (2)
4-10: LGTM.Labels added correctly.
68-75: Good improvement on tooltip formatting.Adding time precision helps distinguish data points at shorter timeframes.
src/features/market-detail/components/charts/volume-chart.tsx (1)
47-49: LGTM.Consistent with rate-chart.tsx changes.
Also applies to: 183-183, 192-193
src/features/market-detail/components/campaign-modal.tsx (3)
18-23: Hardcoded blacklist works for now.Consider moving to config if this list grows. The comment explaining the reason is helpful.
31-43: LGTM on identifier logic.Preferring
opportunityIdentifierwith fallback is clean.
45-51: LGTM.Clean date formatter.
src/utils/merklApi.ts (1)
78-109: LGTM!Clean addition of
nameandopportunityIdentifierfields. Optional chaining handles missingOpportunitydata correctly, and the return type aligns withSimplifiedCampaign.src/features/market-detail/components/market-header.tsx (6)
38-67: LGTM!
WarningBlockis well-structured with proper conditional styling and null handling.
76-97: LGTM!Clean badge component. The pluralization logic works for the current usage patterns.
100-111: LGTM!Simple, clear icon mapping.
376-395: Good accessibility implementation.Proper keyboard handling (Enter/Space), ARIA attributes, and focus management for the expandable section.
397-484: LGTM!Clean framer-motion animation setup. The
overflow-hiddenclass correctly prevents content overflow during height transition.
314-320:size="xs"is valid. The Button component explicitly supports this size variant.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/features/market-detail/components/campaign-modal.tsx (2)
106-138: No empty state when all campaigns are filtered.If all campaigns are blacklisted, the modal body will be empty. Consider adding a fallback message.
Suggested fix
<ModalBody className="space-y-4"> - {filteredCampaigns.map((campaign) => ( + {filteredCampaigns.length === 0 ? ( + <p className="text-center text-gray-500">No active campaigns available.</p> + ) : ( + filteredCampaigns.map((campaign) => ( <CampaignRow key={`${campaign.campaignId}-${campaign.marketId}`} campaign={campaign} /> - ))} + )) + )} </ModalBody>
11-16: Remove unusedactionTypefield from CAMPAIGN_TYPE_CONFIG.The
actionTypeproperty is defined but never accessed anywhere in the codebase. Simplify the config by removing it.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/features/market-detail/components/campaign-modal.tsxsrc/features/market-detail/components/market-header.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 63
File: app/markets/components/MarketRowDetail.tsx:49-52
Timestamp: 2024-10-12T09:23:16.495Z
Learning: When rendering oracle feeds in `ExpandedMarketDetail` (`app/markets/components/MarketRowDetail.tsx`), prefer explicit rendering over iterating keys when dealing with a small number of feeds.
Applied to files:
src/features/market-detail/components/market-header.tsx
📚 Learning: 2025-11-13T20:32:48.908Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 183
File: app/positions/components/RebalanceModal.tsx:301-308
Timestamp: 2025-11-13T20:32:48.908Z
Learning: The TokenIcon component in the codebase accepts a `symbol` prop as part of its valid interface, in addition to `address`, `chainId`, `width`, `height`, and other props.
Applied to files:
src/features/market-detail/components/market-header.tsx
🧬 Code graph analysis (2)
src/features/market-detail/components/market-header.tsx (4)
src/components/shared/token-icon.tsx (1)
TokenIcon(23-95)src/components/shared/address-identity.tsx (1)
AddressIdentity(20-49)src/utils/morpho.ts (1)
getIRMTitle(51-70)src/features/markets/components/oracle/MarketOracle/OracleTypeInfo.tsx (1)
OracleTypeInfo(18-70)
src/features/market-detail/components/campaign-modal.tsx (2)
src/utils/merklTypes.ts (2)
MerklCampaignType(1-1)SimplifiedCampaign(133-159)src/utils/external.ts (1)
getMerklCampaignURL(57-60)
🔇 Additional comments (14)
src/features/market-detail/components/market-header.tsx (10)
1-30: Imports look good.Clean import organization with appropriate dependencies for the animated expandable panel.
38-67: Clean implementation.Early return for empty array, conditional styling based on risk level, proper key usage.
76-97: LGTM.Pluralization handles the expected cases. The count=0 edge case won't occur given current usage.
100-111: LGTM.Simple switch with null fallback for unknown levels.
227-235: Good visual fix for overlapping icons.The
bg-surfacewrapper creates a clean border effect between the overlapping token icons.
291-297: Good precision handling.
toPrecision(6)in tooltip for accuracy across price magnitudes,toFixed(2)for compact display.
314-321: Size change is reasonable.Icon-only dropdown trigger doesn't need larger touch target here.
376-388: Good accessible expand/collapse button.
type="button",aria-expanded, and chevron rotation all handled correctly.
390-398: Animation implementation is clean.AnimatePresence with height/opacity animation and
overflow-hiddenprevents layout jumps.
407-473: Two-column layout with warning blocks works well.Responsive grid, clear section headers with risk icons, proper use of AddressIdentity and OracleTypeInfo components.
src/features/market-detail/components/campaign-modal.tsx (4)
18-23: LGTM!Clear documentation on why the campaign is blacklisted. If this list grows significantly, consider using a
Setfor O(1) lookups.
31-43: LGTM!Clean fallback chain: opportunityIdentifier → type-specific logic → marketId address extraction.
45-51: LGTM!Clean timestamp formatting using locale-aware date display.
53-104: LGTM!Clean component structure. The fallback to
MORPHOSUPPLYconfig (line 57) handles unknown campaign types gracefully. External image domains are already covered by the wildcard pattern in yournext.config.js.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/features/market-detail/components/charts/rate-chart.tsx (1)
47-49: Consider extracting the timeframe type to avoid duplication.The literal union
'1d' | '7d' | '30d' | '3m' | '6m'appears in both the handler signature (line 47) and the cast (line 127). If you add more timeframes later, you'll need to update multiple places.♻️ Suggested refactor
Define a shared type (or import from the store if it already exists there):
type Timeframe = '1d' | '7d' | '30d' | '3m' | '6m'; const handleTimeframeChange = (timeframe: Timeframe) => { setTimeframe(timeframe); }; // ... onValueChange={(value) => handleTimeframeChange(value as Timeframe)}Also applies to: 127-127
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/features/market-detail/components/charts/rate-chart.tsx
🔇 Additional comments (2)
src/features/market-detail/components/charts/rate-chart.tsx (2)
136-137: New timeframe options look good.UI now matches the extended timeframe support.
199-208: New Area for "Rate at Util Target" integrates correctly.All required definitions verified:
CHART_COLORS.apyAtTargetis defined,rateChart-targetGradientis properly rendered via theChartGradientscomponent (which prefixes gradient IDs), andvisibleLines.apyAtTargetis initialized in state. Data prep fromgetChartDataincludes theapyAtTargetfield. Feature is complete.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.