Conversation
🦋 Changeset detectedLatest commit: d4d9a8f The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughComprehensive feature release introducing installments/pay-later payment modes, redesigned home screen with new CardStatus and PortfolioSummary components, font unification to SplineSans, widespread design token standardization across spacing, new payment-related UI sheets, hook refactoring, and Spanish translation expansion. Includes Maestro E2E test updates validating new payment flows. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Home as Home Component
participant CardStatus as CardStatus Component
participant PayModeSheet as PayModeSheet
participant InstallmentsSheet as InstallmentsSheet
participant useInstallmentRates as useInstallmentRates Hook
participant mutateMode as setCardMode Mutation
participant Backend as Backend API
User->>Home: Opens Home Screen
Home->>CardStatus: Renders with mode, collateral, creditLimit
User->>CardStatus: Taps "Now/Later" Toggle
CardStatus->>PayModeSheet: Opens mode selection
User->>PayModeSheet: Selects "Pay Later"
PayModeSheet->>CardStatus: Calls onModeChange
CardStatus->>InstallmentsSheet: Opens installment selector
User->>InstallmentsSheet: Selects installment count
InstallmentsSheet->>useInstallmentRates: Requests APR for selection
useInstallmentRates->>Backend: Queries market data
Backend-->>useInstallmentRates: Returns rates, utilization
useInstallmentRates-->>InstallmentsSheet: Returns payment schedule
InstallmentsSheet->>User: Displays APR and payments
User->>InstallmentsSheet: Confirms installment count
InstallmentsSheet->>mutateMode: Calls onModeChange(installmentCount)
mutateMode->>Backend: POST card mode change
Backend-->>mutateMode: Confirms update, returns new limits
mutateMode->>Home: Updates state optimistically
Home->>CardStatus: Re-renders with new mode/limits
CardStatus-->>User: Displays updated spending limit
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 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 |
Summary of ChangesHello @dieguezguille, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a comprehensive redesign of the application's core user interface, specifically targeting the home and payments sections. The changes aim to modernize the application's appearance, improve navigation, and introduce new functionalities such as an installments calculator and enhanced card management options. The update focuses on providing a more intuitive and visually appealing experience for users interacting with their financial data and card services. Highlights
Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Prevent Tests Dashboard |
Greptile Summaryredesigned home screen with new installments payment system and visual refresh
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
Start[User opens Home screen] --> CardStatus[CardStatus Component]
CardStatus --> Toggle{Pay Mode Toggle}
Toggle -->|Now mode = 0| DebitView[Shows Spending Limit]
Toggle -->|Later mode > 0| CreditView[Shows Credit Limit]
Toggle --> InstallmentsButton[User taps Later toggle]
InstallmentsButton -->|mode = 0| SetMode[Set mode to lastInstallments ?? 1]
InstallmentsButton -->|mode > 0| OpenSheet[Open InstallmentsSheet]
OpenSheet --> SelectInstallments[InstallmentsSheet]
SelectInstallments --> LoadRates[useInstallmentRates hook]
LoadRates --> CalcRates[Calculate APR for 1-12 installments]
CalcRates --> Display[Display horizontal scroll cards]
Display --> UserSelect[User selects installment count]
UserSelect --> UpdateMode[Call onModeChange with selected count]
UpdateMode --> MutateMode[mutateMode API call]
MutateMode --> UpdateCache[Update queryClient cache]
CardStatus --> LearnMore[User taps Learn More]
LearnMore --> PayModeSheet[PayModeSheet Component]
PayModeSheet --> ExplainModes[Explain Now vs Later modes]
CreditView --> Payment[User makes purchase]
Payment --> CreateDebt[Debt created with maturity]
CreateDebt --> HomePayments[OverduePayments/UpcomingPayments]
HomePayments --> PaymentClick[User clicks payment]
PaymentClick --> PayComponent[Pay Component]
PayComponent --> AssetSelect[Select payment asset]
AssetSelect --> CalcRoute[Calculate swap route if needed]
CalcRoute --> RepayDebt[Execute repayAtMaturity]
Last reviewed commit: 1220ff6 |
| <Modal transparent visible animationType="fade" statusBarTranslucent> | ||
| <View style={StyleSheet.absoluteFill}> | ||
| <SVG width={screenWidth} height={screenHeight}> | ||
| <Defs> | ||
| <Mask id="cutout"> | ||
| <Rect width={screenWidth} height={screenHeight} fill="white" /> | ||
| <Rect | ||
| transform={[{ translateX: cutout.x }, { translateY: cutout.y }]} | ||
| width={cutout.width} | ||
| height={cutout.height} | ||
| rx={cutoutRadius} | ||
| fill="black" | ||
| /> | ||
| </Mask> | ||
| </Defs> | ||
| <Rect width={screenWidth} height={screenHeight} fill="rgba(0,0,0,0.56)" mask="url(#cutout)" /> | ||
| <Rect | ||
| transform={[{ translateX: cutout.x }, { translateY: cutout.y }]} | ||
| width={cutout.width} | ||
| height={cutout.height} | ||
| rx={cutoutRadius} | ||
| fill="none" | ||
| stroke="white" | ||
| strokeWidth={2} | ||
| /> | ||
| </SVG> | ||
| </View> | ||
| <Pressable | ||
| aria-label={t("Tap here to change the number of installments")} | ||
| style={[ | ||
| styles.cutoutPress, | ||
| { top: cutout.y, left: cutout.x, width: cutout.width, height: cutout.height, borderRadius: cutoutRadius }, | ||
| ]} | ||
| onPress={() => { | ||
| onPress(); | ||
| onDismiss(); | ||
| }} | ||
| /> | ||
| <Theme name="light"> | ||
| <YStack | ||
| position="absolute" | ||
| top={tooltipTop} | ||
| left={tooltipLeft} | ||
| width={200} | ||
| backgroundColor="$backgroundSoft" | ||
| borderRadius="$r3" | ||
| padding="$s4" | ||
| shadowColor="$uiNeutralSecondary" | ||
| shadowOffset={{ width: 0, height: 2 }} | ||
| shadowOpacity={0.15} | ||
| shadowRadius={8} | ||
| onPress={() => { | ||
| onPress(); | ||
| onDismiss(); | ||
| }} | ||
| > | ||
| <View | ||
| position="absolute" | ||
| top={-6} | ||
| left={arrowLeft} | ||
| width={12} | ||
| height={12} | ||
| backgroundColor="$backgroundSoft" | ||
| borderRadius={2} | ||
| transform={[{ rotate: "45deg" }]} | ||
| /> | ||
| <Text footnote textAlign="center"> | ||
| {t("Tap here to change the number of installments")} | ||
| </Text> | ||
| </YStack> | ||
| </Theme> | ||
| </Modal> | ||
| ); |
There was a problem hiding this comment.
🚩 InstallmentsSpotlight has no background dismiss and no Android back button handler
The InstallmentsSpotlight component (src/components/home/InstallmentsSpotlight.tsx) renders a Modal with a dark overlay but provides no onRequestClose prop (Android back button) and no pressable overlay to dismiss. Users can only dismiss by tapping the cutout target or the tooltip. This forces user engagement with the spotlight, which may be intentional for onboarding. If the target ref measurement fails (e.g., the element scrolled off-screen or was unmounted), the component returns null after 10 attempts (5 seconds), so it won't get permanently stuck.
Was this helpful? React with 👍 or 👎 to provide feedback.
| return useMemo(() => { | ||
| if (!market) return; | ||
| const now = Math.floor(Date.now() / 1000); | ||
| const nextMaturity = now - (now % MATURITY_INTERVAL) + MATURITY_INTERVAL; | ||
| const firstMaturity = nextMaturity - now < MIN_BORROW_INTERVAL ? nextMaturity + MATURITY_INTERVAL : nextMaturity; | ||
| if (amount <= 0n) { | ||
| const installments = []; | ||
| for (let count = 1; count <= MAX_INSTALLMENTS; count++) { | ||
| installments.push({ count, payments: Array.from<bigint>({ length: count }).fill(0n), rate: 0n, total: 0n }); | ||
| } | ||
| return { installments, firstMaturity }; | ||
| } | ||
| const { | ||
| fixedPools, | ||
| floatingBackupBorrowed, | ||
| floatingUtilization, | ||
| interestRateModel: { parameters }, | ||
| totalFloatingBorrowAssets, | ||
| totalFloatingDepositAssets, | ||
| } = market; | ||
| const marketUtilization = globalUtilization( | ||
| totalFloatingDepositAssets, | ||
| totalFloatingBorrowAssets, | ||
| floatingBackupBorrowed, | ||
| ); | ||
| const borrowImpact = totalFloatingDepositAssets > 0n ? (amount * WAD - 1n) / totalFloatingDepositAssets + 1n : 0n; | ||
| try { | ||
| const installments = []; | ||
| for (let count = 1; count <= MAX_INSTALLMENTS; count++) { | ||
| const poolUtilizations = fixedPools | ||
| .filter(({ maturity }) => maturity >= firstMaturity && maturity < firstMaturity + count * MATURITY_INTERVAL) | ||
| .map(({ supplied, borrowed }) => fixedUtilization(supplied, borrowed, totalFloatingDepositAssets)); | ||
| if (poolUtilizations.length === 0) { | ||
| installments.push({ count, payments: undefined, rate: 0n, total: 0n }); | ||
| continue; | ||
| } | ||
| if (count === 1) { | ||
| const rate = fixedRate( | ||
| firstMaturity, | ||
| fixedPools.length, | ||
| (poolUtilizations[0] ?? 0n) + borrowImpact, | ||
| floatingUtilization, | ||
| marketUtilization + borrowImpact, | ||
| parameters, | ||
| now, | ||
| ); | ||
| const fee = (amount * rate * BigInt(firstMaturity - now)) / (WAD * ONE_YEAR); | ||
| const total = amount + fee; | ||
| installments.push({ count, payments: [total], rate, total }); | ||
| continue; | ||
| } | ||
| const { installments: payments, effectiveRate } = splitInstallments( | ||
| amount, | ||
| totalFloatingDepositAssets, | ||
| firstMaturity, | ||
| fixedPools.length, | ||
| poolUtilizations, | ||
| floatingUtilization, | ||
| marketUtilization, | ||
| parameters, | ||
| now, | ||
| ); | ||
| installments.push({ count, payments, rate: effectiveRate, total: payments.reduce((a, b) => a + b, 0n) }); | ||
| } | ||
| return { installments, firstMaturity }; | ||
| } catch (error) { | ||
| reportError(error); | ||
| } | ||
| }, [market, amount]); |
There was a problem hiding this comment.
🚩 useInstallmentRates captures now inside useMemo without dependency tracking
Unlike useInstallments.ts where timestamp is a function parameter included in the useMemo dependency array (recomputing on every render), useInstallmentRates.ts:23 computes now = Math.floor(Date.now() / 1000) inside the memo with only [market, amount] as dependencies. This means the rates and firstMaturity calculation become stale until market data refreshes. For the InstallmentsSheet use case (brief user interaction), this is unlikely to cause visible issues. However, the inconsistency with the established pattern in useInstallments.ts:16 is worth noting — the existing hook recomputes every second due to timestamp being in deps.
Was this helpful? React with 👍 or 👎 to provide feedback.
closes #501, closes #599, closes #713
Summary by CodeRabbit
New Features
Style & UI Improvements
Bug Fixes
Greptile Summary
this pr implements a comprehensive home screen redesign focused on the new pay mode selection feature, allowing users to toggle between instant payments (pay now/debit mode) and installment-based credit (pay later/credit mode). the changes introduce:
Amountcomponent, addedButtonColumnandButtonLabelvariants to styled button, redesigned portfolio summary with asset logo previewsthe implementation integrates with existing financial calculations from
@exactly/liband maintains consistency with the project's established patterns.Confidence Score: 4/5
useInstallmentRates.tsline 29 which has already been flagged in previous comments.Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Home Screen] --> B{Card Exists?} B -->|Yes| C[CardStatus Component] C --> D[Pay Mode Toggle] D --> E{User Selects Mode} E -->|Pay Now| F[Debit Mode - mode=0] E -->|Pay Later| G[Credit Mode - mode>0] G --> H[InstallmentsSheet] H --> I[useInstallmentRates Hook] I --> J[Calculate APR for 1-12 installments] J --> K[Display rates in scrollable cards] K --> L[User selects installment count] L --> M[Update card mode via setCardMode API] C --> N[LimitPaginator] N --> O{Mode Check} O -->|mode=0| P[Show Spending Limit] O -->|mode>0| Q[Show Credit Limit] D --> R[Learn More] R --> S[PayModeSheet] S --> T[Explain Pay Now vs Pay Later] A --> U[PortfolioSummary] U --> V[Display assets with Amount component] V --> W[Show APR & collateral]Last reviewed commit: b87e85f