Skip to content

Feat/create message placeholder page#216

Merged
respp merged 13 commits intoStellar-Rent:mainfrom
FrancoEspinosa08:feat/create-message-placeholder-page
Jan 30, 2026
Merged

Feat/create message placeholder page#216
respp merged 13 commits intoStellar-Rent:mainfrom
FrancoEspinosa08:feat/create-message-placeholder-page

Conversation

@FrancoEspinosa08
Copy link
Contributor

@FrancoEspinosa08 FrancoEspinosa08 commented Jan 29, 2026

StellarRent Logo

Pull Request | StellarRent

📝 Summary

Provide a brief description of what this PR accomplishes.

🔗 Related Issues

Closes #(issue number) (Replace with the actual issue number).

🔄 Changes Made

Provide a general description of the changes. Include any relevant background information or context to help reviewers understand the purpose of this PR.

🖼️ Current Output

Provide visual evidence of the changes:

  • For small changes: Screenshots.
  • For large changes: Video or Loom link.

🧪 Testing

If applicable, describe the tests performed. Include screenshots, test outputs, or any resources that help reviewers understand how the changes were tested.

✅ Testing Checklist

  • Unit tests added/modified
  • Integration tests performed
  • Manual tests executed
  • All tests pass in CI/CD

⚠️ Potential Risks

List any possible issues that might arise with this change.

🚀 Next Steps & Improvements

This change lays a solid foundation for further optimizations. Some areas that could benefit from future improvements include:

  • 🔹 Performance optimization
  • 🔹 Increased test coverage
  • 🔹 Potential user experience enhancements

💬 Comments

Any additional context, questions, or considerations for reviewers.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added messaging page for user communication
    • Introduced new navigation layout with sidebar and top navigation bar
  • Improvements

    • Enhanced property search interface with refined sorting and filtering
    • Improved invitations page UI with streamlined controls
    • Updated property detail and booking experience with better information display
    • Consolidated navigation menu for consistent user experience
    • Added image error handling on property pages

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

The PR refactors the web app's layout, authentication, and search infrastructure by introducing a two-column layout with Navbar and RightSidebar, creating a new messages page scaffold, consolidating menu items across user roles, simplifying auth and role derivation logic, updating Stellar integration for mainnet/testnet USDC issuer support, converting the property detail page to client-side rendering, and streamlining component state management across multiple pages.

Changes

Cohort / File(s) Summary
Layout Restructuring
apps/web/src/app/layout.tsx
Updated root layout with two-column design featuring Navbar at top, main content with reduced width, and fixed RightSidebar; changed metadata (title/description), language, and body background color (#0B1221); added reserved padding (pr-12) for sidebar.
New Pages
apps/web/src/app/messages/page.tsx
Created new client-side messages page with two-column chat UI scaffold featuring search input in left sidebar (w-80) and placeholder prompts in right area; includes local searchQuery state via useState.
Search Page Refactoring
apps/web/src/app/search/page.tsx
Introduced PAGE_SIZE constant (3); renamed state variables (sort→sortOrder, minMax→priceRange, center/markers→mapCenter/mapMarkers, checked→isChecked, location→locationQuery, aDist/bDist→distA/distB); updated useMemo dependencies and filter/sort logic accordingly; adjusted async loading simulation timing.
Menu Items Consolidation
apps/web/src/constants/menu-items.ts
Consolidated role-based menus by introducing internal ICON_* constants and deriving TENANT_MENU_ITEMS, HOST_MENU_ITEMS, and DUAL_MENU_ITEMS from shared GUEST_MENU_ITEMS; reduced from per-role explicit arrays to a single composed set.
User Role & Auth Hooks
apps/web/src/hooks/useUserRole.tsx, apps/web/src/hooks/auth/use-auth.tsx
Refactored useUserRole with fallback API-to-localStorage handling, consolidated host/role logic (role='dual' when verified + hasProperties), renamed validation array; significantly simplified use-auth by removing OAuth/Freighter setup, balance/payment logic, and localStorage restoration, leaving no-op stubs for public methods.
Stellar Integration
apps/web/src/lib/config/config.ts, apps/web/src/lib/stellar.ts
Added hardcoded MAINNET_USDC_ISSUER/TESTNET_USDC_ISSUER constants with environment variable fallbacks via getUsdcIssuer(); replaced throw-based error handling with console warnings; updated stellar.ts to add FreighterSignResponse interface, use getUSDCAsset validator, refactored createPaymentTransaction/submitTransaction/processPayment/getUSDCBalance for XDR-based submission and asset validation.
Theme & Providers
apps/web/src/components/shared/layout/providers.tsx, apps/web/src/lib/stellar-social-sdk.ts
Replaced dynamic ThemeProvider loading with direct imports and added ThemePortalSync component for theme synchronization; changed stellar-social-sdk from static to runtime-resolved exports via getSDK() function and added lightweight type definitions (AuthMethod, UserRole, SocialAuthConfig, StellarUser).
Page Refactoring
apps/web/src/app/property/[id]/page.tsx, apps/web/src/app/invitations/page.tsx, apps/web/src/app/search/property/page.tsx
Converted property page from server-side async to client-side component with mock data and computed pricing; refactored invitations page with streamlined layout, removed IconContainer, simplified filter/sort handlers, added MobileMenuDrawer with accessibility; updated property search page with hardened calculations, inline state updates, image error handling, and removed crypto-specific text.
Component Updates
apps/web/src/app/dashboard/host-dashboard/components/AddPropertyModal.tsx
Refactored onChange handlers from object spread to functional state updates; removed entire Photos section UI; tidied up className strings and button styling.
Build Configuration
apps/web/next.config.js
Added ESLint suppression (ignoreDuringBuilds: true) and expanded webpack config signature; enabled topLevelAwait via experiments; added sodium-native→sodium-universal alias mapping.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • respp

🐰 A layout so neat, with sidebars aligned,
Messages and menus refined by design,
Auth simplified, search variables renamed,
Stellar chains dancing—mainnet and test,
From client to server, refactored to best!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Feat/create message placeholder page' is vague and only partially related to the actual changeset. While a messages placeholder page is introduced, the PR contains extensive refactoring across 15+ files including layout restructuring, authentication changes, Stellar configuration updates, and multiple component rewrites. Consider updating the title to reflect the broader scope: e.g., 'Refactor: restructure layout, auth, and Stellar config with messages page' or provide a more specific title for the actual primary change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/app/search/page.tsx (1)

78-103: Update PropertyGrid to accept and use the passed props; then remove the as any cast.

PropertyGrid is currently exported as a no-argument component that ignores the properties and onLoadMore props being passed to it. The as any cast hides a real type error. Update the component to accept { properties, onLoadMore } props, use the passed properties instead of mockProperties, and call the callback when needed. Then render PropertyGrid directly without the type cast.

Fix outline
- export const PropertyGrid = () => {
+ interface PropertyGridProps {
+   properties: Property[];
+   onLoadMore: () => void;
+ }
+ 
+ export const PropertyGrid = ({ properties, onLoadMore }: PropertyGridProps) => {
    return (
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
-       {mockProperties.map((property) => (
+       {properties.map((property) => (
          <PropertyCard key={property.id} property={property} />
        ))}
      </div>
    );
  };

And in search/page.tsx:

- const Grid = PropertyGrid as any;
  ...
- <Grid properties={visibleProperties} onLoadMore={loadNextPage} />
+ <PropertyGrid properties={visibleProperties} onLoadMore={loadNextPage} />
🤖 Fix all issues with AI agents
In `@apps/web/src/constants/menu-items.ts`:
- Line 14: ICON_SETTINGS has a semantic mismatch: its label is "Settings" but
href points to "/invitations"; update the constant (ICON_SETTINGS) so label and
href match—either change label to "Invitations" if the target is correct or
change href to "/settings" (or the actual settings route used elsewhere) so the
"Settings" label navigates to the settings page; adjust only ICON_SETTINGS in
apps/web/src/constants/menu-items.ts to keep naming consistent with other menu
items.

In `@apps/web/src/lib/config/config.ts`:
- Line 22: The current assignment of USDC_ISSUER (export const USDC_ISSUER =
envIssuer || TESTNET_USDC_ISSUER) allows silently falling back to
TESTNET_USDC_ISSUER on mainnet; update the logic in config so: determine
envIssuer from NEXT_PUBLIC_USDC_ISSUER_MAINNET/NEXT_PUBLIC_USDC_ISSUER, then if
STELLAR_NETWORK === 'testnet' allow fallback to TESTNET_USDC_ISSUER, but if
STELLAR_NETWORK === 'mainnet' either use a provided
NEXT_PUBLIC_USDC_ISSUER_MAINNET or fall back to the known Circle mainnet issuer
(GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN) or throw a clear
error; change the code referencing USDC_ISSUER/envIssuer/TESTNET_USDC_ISSUER to
implement this branching so mainnet never silently uses the testnet issuer.
🧹 Nitpick comments (9)
apps/web/src/constants/menu-items.ts (3)

10-16: Add explicit type annotations to icon constants.

The ICON_* constants lack explicit MenuItem type annotations. While TypeScript validates them when assigned to MenuItem[], adding explicit types catches errors at the definition site and improves IDE support.

♻️ Suggested refactor
-const ICON_MENU = { id: 'menu', src: '/icons/menu.webp', alt: 'Menu', label: 'Menu', href: '#' };
-const ICON_SEARCH = { id: 'search', src: '/icons/search.webp', alt: 'Search', label: 'Find a Property', href: '/search', withContainer: true };
-const ICON_FAVORITES = { id: 'favorites', src: '/icons/heart.webp', alt: 'Favorites', label: 'Favorites', href: '/dashboard/guest?tab=bookings' };
-const ICON_MESSAGES = { id: 'messages', src: '/icons/send.webp', alt: 'Messages', label: 'Messages', href: '/messages', withContainer: true };
-const ICON_SETTINGS = { id: 'settings', src: '/icons/settings.webp', alt: 'Settings', label: 'Settings', href: '/invitations' };
-const ICON_LOCK = { id: 'lock', src: '/icons/lock.webp', alt: 'Lock', label: 'Private', href: '#' };
-const ICON_APPLICATIONS = { id: 'applications', src: '/icons/message.webp', alt: 'Applications', label: 'Applications', href: '/applications' };
+const ICON_MENU: MenuItem = { id: 'menu', src: '/icons/menu.webp', alt: 'Menu', label: 'Menu', href: '#' };
+const ICON_SEARCH: MenuItem = { id: 'search', src: '/icons/search.webp', alt: 'Search', label: 'Find a Property', href: '/search', withContainer: true };
+const ICON_FAVORITES: MenuItem = { id: 'favorites', src: '/icons/heart.webp', alt: 'Favorites', label: 'Favorites', href: '/dashboard/guest?tab=bookings' };
+const ICON_MESSAGES: MenuItem = { id: 'messages', src: '/icons/send.webp', alt: 'Messages', label: 'Messages', href: '/messages', withContainer: true };
+const ICON_SETTINGS: MenuItem = { id: 'settings', src: '/icons/settings.webp', alt: 'Settings', label: 'Settings', href: '/invitations' };
+const ICON_LOCK: MenuItem = { id: 'lock', src: '/icons/lock.webp', alt: 'Lock', label: 'Private', href: '#' };
+const ICON_APPLICATIONS: MenuItem = { id: 'applications', src: '/icons/message.webp', alt: 'Applications', label: 'Applications', href: '/applications' };

22-25: Inconsistent language in comments.

Comments use Spanish ("Flecha", "Correo") while the rest of the codebase appears to be in English. Consider updating to English for consistency.

♻️ Suggested fix
-  ICON_MESSAGES,     // Flecha (send.webp)
+  ICON_MESSAGES,     // Arrow/Send icon (send.webp)
   ICON_SETTINGS,
   ICON_LOCK,
-  ICON_APPLICATIONS, // Correo (message.webp)
+  ICON_APPLICATIONS, // Mail/Message icon (message.webp)

28-30: Role-specific menu arrays are identical.

TENANT_MENU_ITEMS, HOST_MENU_ITEMS, and DUAL_MENU_ITEMS are all shallow copies of GUEST_MENU_ITEMS. If role-based differentiation is planned for the future, this structure is reasonable. Otherwise, consumers could reference GUEST_MENU_ITEMS directly to reduce indirection.

apps/web/src/hooks/useUserRole.tsx (2)

25-43: Remove Spanish comments and unnecessary explicit typing.

The codebase appears to use English; Spanish comments reduce consistency. Also, the explicit (prev: RoleInfo) typing is unnecessary since TypeScript infers the type from useState<RoleInfo>.

Suggested cleanup
-      // 1. Si no está autenticado o no hay usuario, retornamos guest de inmediato
+      // Early return for unauthenticated users
       if (!isAuthenticated || !user) {
         setRoleInfo({
           role: 'guest',
           canAccessHostDashboard: false,
           hasProperties: false,
         });
         setIsLoading(false);
         return;
       }

-      // 2. Extraemos el ID. Si no existe, no llamamos a la API
+      // Extract user ID for API call
       const userId = user.publicKey || user.id;
       if (!userId) {
-        // CORRECCIÓN: Tipamos 'prev' como RoleInfo para eliminar el error 7006
-        setRoleInfo((prev: RoleInfo) => ({ ...prev, role: 'guest' }));
+        setRoleInfo({
+          role: 'guest',
+          canAccessHostDashboard: false,
+          hasProperties: false,
+        });
         setIsLoading(false);
         return;
       }

78-105: Extract duplicated role determination logic into a helper function.

The role calculation logic (lines 89-98) duplicates lines 56-65. This violates DRY and increases maintenance burden—any fix to the role logic must be applied in both places.

Suggested refactor
+const determineRole = (
+  hostStatus: string | undefined,
+  hasProperties: boolean
+): Pick<RoleInfo, 'role' | 'canAccessHostDashboard'> => {
+  if (hostStatus === 'verified' && hasProperties) {
+    return { role: 'dual', canAccessHostDashboard: true };
+  }
+  if (hostStatus === 'verified') {
+    return { role: 'host', canAccessHostDashboard: false };
+  }
+  return { role: 'guest', canAccessHostDashboard: false };
+};

 export function useUserRole(): UseUserRoleReturn {
   // ... state and auth checks ...

   // In API success path:
-  let role: UserRole = 'guest';
-  let canAccessHostDashboard = false;
-
-  if (hostStatus === 'verified' && hasProperties) {
-    role = 'dual';
-    canAccessHostDashboard = true;
-  } else if (hostStatus === 'verified') {
-    role = 'host';
-    canAccessHostDashboard = false;
-  }
+  const { role, canAccessHostDashboard } = determineRole(hostStatus, hasProperties);

   // Similarly in fallback path

Also consider logging the API error in development to aid debugging:

-        } catch (_apiError) {
+        } catch (apiError) {
+          if (process.env.NODE_ENV === 'development') {
+            console.warn('Failed to fetch user profile, falling back to localStorage:', apiError);
+          }
           // Fallback to localStorage if API fails
apps/web/src/lib/stellar.ts (3)

8-19: Consider using stellar-sdk's built-in key validation.

The current validation (startsWith('G') && length === 56) is a basic format check. For more robust validation, stellar-sdk provides StrKey.isValidEd25519PublicKey() which also validates the checksum.

♻️ Proposed enhancement using StrKey validation
-import { Asset, Horizon, Operation, TransactionBuilder, Transaction } from 'stellar-sdk';
+import { Asset, Horizon, Operation, TransactionBuilder, Transaction, StrKey } from 'stellar-sdk';
 const getUSDCAsset = () => {
-  if (USDC_ISSUER && USDC_ISSUER.startsWith('G') && USDC_ISSUER.length === 56) {
+  if (USDC_ISSUER && StrKey.isValidEd25519PublicKey(USDC_ISSUER)) {
     return new Asset('USDC', USDC_ISSUER);
   }

87-93: Consider adding type declarations for Freighter API instead of @ts-ignore.

Using @ts-ignore suppresses all type checking. A cleaner approach is to declare the Freighter API types, which improves IDE support and catches potential issues.

♻️ Proposed type declaration for Freighter API

Add a type declaration file (e.g., types/freighter.d.ts) or at the top of this file:

declare global {
  interface Window {
    freighterApi?: {
      signTransaction(xdr: string, opts?: { networkPassphrase?: string }): Promise<string>;
      isConnected(): Promise<boolean>;
      getPublicKey(): Promise<string>;
    };
  }
}

Then remove the @ts-ignore comments:

-    // `@ts-ignore`: Freighter API global access
     if (typeof window === 'undefined' || !window.freighterApi) {
       throw new Error('Freighter wallet not found');
     }
-    
-    // `@ts-ignore`: Freighter API global access
     const signedTransaction = await window.freighterApi.signTransaction(transactionXDR);

57-70: Use TransactionBuilder.fromXDR() instead of the Transaction constructor.

Per the official stellar-sdk v13 documentation, TransactionBuilder.fromXDR(signedTransactionXDR, NETWORK_PASSPHRASE) is the recommended approach for reconstructing transactions from XDR. The current new Transaction(xdr, networkPassphrase) works but directs developers to use TransactionBuilder.fromXDR(). The key advantage is that TransactionBuilder.fromXDR() automatically returns the correct type (Transaction or FeeBumpTransaction), whereas the constructor always returns a Transaction instance.

apps/web/src/app/messages/page.tsx (1)

15-17: Make the search icon non-interactive so clicks focus the input.

This prevents the icon from intercepting pointer events.

🛠️ Proposed tweak
-            <Search className="absolute left-4 top-2.5 h-4 w-4 text-gray-500" aria-hidden="true" />
+            <Search className="absolute left-4 top-2.5 h-4 w-4 text-gray-500 pointer-events-none" aria-hidden="true" />

Copy link
Contributor

@respp respp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job! Once you've fixed the merge conflicts, I'll get this merged.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@apps/web/src/constants/menu-items.ts`:
- Around line 19-25: ICON_FAVORITES currently has a semantic mismatch: its label
"Favorites" points to /dashboard/guest?tab=bookings; update the constant
(ICON_FAVORITES) so label and href match—either change label to "Bookings" to
reflect href or change href to /dashboard/guest?tab=favorites to match the
"Favorites" label; ensure the alt and id remain consistent with the chosen
meaning.
- Around line 36-42: ICON_INVITATIONS currently points to the settings icon;
update the asset and alt text to match the "Invitations" semantics by changing
ICON_INVITATIONS.src to an invitation-themed file (for example
'/icons/invitations.webp' or '/icons/envelope.webp') and adjust
ICON_INVITATIONS.alt to "Invitations" or "Envelope" as appropriate so the icon,
alt and label/href all align.

In `@apps/web/src/lib/config/config.ts`:
- Around line 17-25: The function getUsdcIssuer currently treats any
non-'mainnet' value as testnet; update getUsdcIssuer to validate STELLAR_NETWORK
explicitly (accept only 'mainnet' or 'testnet') and fail fast on invalid values
by throwing an Error (or at minimum logging a loud warning and throwing) so
misconfigured environments don't silently use TESTNET_USDC_ISSUER; reference
STELLAR_NETWORK and the existing symbols NEXT_PUBLIC_USDC_ISSUER_MAINNET,
MAINNET_USDC_ISSUER, NEXT_PUBLIC_USDC_ISSUER_TESTNET, TESTNET_USDC_ISSUER and
implement the guard at the start of getUsdcIssuer.
🧹 Nitpick comments (2)
apps/web/src/components/shared/layout/providers.tsx (1)

12-20: Consider using classList or a data attribute to avoid overwriting other classes.

The assignment portal.className = resolvedTheme replaces the entire className of the portal element. If theme-portal-root has (or later needs) additional classes for layout or styling, they would be lost.

♻️ Safer alternative using classList
 function ThemePortalSync() {
   const { resolvedTheme } = useTheme();
   React.useEffect(() => {
     const portal =
       typeof window !== 'undefined' ? document.getElementById('theme-portal-root') : null;
-    if (portal && resolvedTheme) portal.className = resolvedTheme;
+    if (portal && resolvedTheme) {
+      portal.classList.remove('light', 'dark');
+      portal.classList.add(resolvedTheme);
+    }
   }, [resolvedTheme]);
   return null;
 }

Alternatively, consider using a data-theme attribute instead of a class if you control the portal's CSS.

apps/web/src/constants/menu-items.ts (1)

63-65: Consider simplifying identical role-based exports.

TENANT_MENU_ITEMS, HOST_MENU_ITEMS, and DUAL_MENU_ITEMS are currently identical copies of GUEST_MENU_ITEMS. If role-specific menus are planned for the future, this is fine as-is. Otherwise, you could simplify by re-exporting or using a type alias.

-export const TENANT_MENU_ITEMS: MenuItem[] = [...GUEST_MENU_ITEMS];
-export const HOST_MENU_ITEMS: MenuItem[] = [...GUEST_MENU_ITEMS];
-export const DUAL_MENU_ITEMS: MenuItem[] = [...GUEST_MENU_ITEMS];
+// Re-export if menus remain identical across roles
+export { GUEST_MENU_ITEMS as TENANT_MENU_ITEMS };
+export { GUEST_MENU_ITEMS as HOST_MENU_ITEMS };
+export { GUEST_MENU_ITEMS as DUAL_MENU_ITEMS };

Comment on lines +19 to +25
const ICON_FAVORITES = {
id: 'favorites',
src: '/icons/heart.webp',
alt: 'Favorites',
label: 'Favorites',
href: '/dashboard/guest?tab=bookings',
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Semantic mismatch: "Favorites" label points to bookings tab.

ICON_FAVORITES has label "Favorites" but navigates to /dashboard/guest?tab=bookings. This mirrors the previously flagged Settings/invitations mismatch. Consider either:

  • Renaming the label to reflect the destination (e.g., "Bookings")
  • Updating the href to an actual favorites page (e.g., /dashboard/guest?tab=favorites)
🤖 Prompt for AI Agents
In `@apps/web/src/constants/menu-items.ts` around lines 19 - 25, ICON_FAVORITES
currently has a semantic mismatch: its label "Favorites" points to
/dashboard/guest?tab=bookings; update the constant (ICON_FAVORITES) so label and
href match—either change label to "Bookings" to reflect href or change href to
/dashboard/guest?tab=favorites to match the "Favorites" label; ensure the alt
and id remain consistent with the chosen meaning.

Comment on lines +36 to +42
const ICON_INVITATIONS = {
id: 'invitations',
src: '/icons/settings.webp',
alt: 'Invitations',
label: 'Invitations',
href: '/invitations',
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Icon asset doesn't match the "Invitations" semantics.

While the label/href mismatch has been corrected, the icon source still references /icons/settings.webp. For visual consistency, consider using an invitation-themed icon (e.g., envelope or bell icon) instead of the settings gear.

🤖 Prompt for AI Agents
In `@apps/web/src/constants/menu-items.ts` around lines 36 - 42, ICON_INVITATIONS
currently points to the settings icon; update the asset and alt text to match
the "Invitations" semantics by changing ICON_INVITATIONS.src to an
invitation-themed file (for example '/icons/invitations.webp' or
'/icons/envelope.webp') and adjust ICON_INVITATIONS.alt to "Invitations" or
"Envelope" as appropriate so the icon, alt and label/href all align.

Comment on lines 17 to 25
// 2. Lógica de selección segura
const getUsdcIssuer = () => {
if (STELLAR_NETWORK === 'mainnet') {
// En Mainnet, prioriza la env var, pero si no está, usa el emisor real de Mainnet
return process.env.NEXT_PUBLIC_USDC_ISSUER_MAINNET || MAINNET_USDC_ISSUER;
}
// En Testnet, usa la env var o el fallback de testnet
return process.env.NEXT_PUBLIC_USDC_ISSUER_TESTNET || TESTNET_USDC_ISSUER;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate STELLAR_NETWORK to avoid unintended testnet fallback.

Any unsupported value currently falls through to the testnet issuer, which can silently misroute transactions if the env is misconfigured. Add an explicit guard so invalid values fail fast or at least warn loudly.

🛠️ Suggested fix (explicit guard)
 const getUsdcIssuer = () => {
   if (STELLAR_NETWORK === 'mainnet') {
     // En Mainnet, prioriza la env var, pero si no está, usa el emisor real de Mainnet
     return process.env.NEXT_PUBLIC_USDC_ISSUER_MAINNET || MAINNET_USDC_ISSUER;
   }
-  // En Testnet, usa la env var o el fallback de testnet
-  return process.env.NEXT_PUBLIC_USDC_ISSUER_TESTNET || TESTNET_USDC_ISSUER;
+  if (STELLAR_NETWORK === 'testnet') {
+    // En Testnet, usa la env var o el fallback de testnet
+    return process.env.NEXT_PUBLIC_USDC_ISSUER_TESTNET || TESTNET_USDC_ISSUER;
+  }
+  throw new Error(`Unsupported STELLAR_NETWORK value: ${STELLAR_NETWORK}`);
 };
📝 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.

Suggested change
// 2. Lógica de selección segura
const getUsdcIssuer = () => {
if (STELLAR_NETWORK === 'mainnet') {
// En Mainnet, prioriza la env var, pero si no está, usa el emisor real de Mainnet
return process.env.NEXT_PUBLIC_USDC_ISSUER_MAINNET || MAINNET_USDC_ISSUER;
}
// En Testnet, usa la env var o el fallback de testnet
return process.env.NEXT_PUBLIC_USDC_ISSUER_TESTNET || TESTNET_USDC_ISSUER;
};
// 2. Lógica de selección segura
const getUsdcIssuer = () => {
if (STELLAR_NETWORK === 'mainnet') {
// En Mainnet, prioriza la env var, pero si no está, usa el emisor real de Mainnet
return process.env.NEXT_PUBLIC_USDC_ISSUER_MAINNET || MAINNET_USDC_ISSUER;
}
if (STELLAR_NETWORK === 'testnet') {
// En Testnet, usa la env var o el fallback de testnet
return process.env.NEXT_PUBLIC_USDC_ISSUER_TESTNET || TESTNET_USDC_ISSUER;
}
throw new Error(`Unsupported STELLAR_NETWORK value: ${STELLAR_NETWORK}`);
};
🤖 Prompt for AI Agents
In `@apps/web/src/lib/config/config.ts` around lines 17 - 25, The function
getUsdcIssuer currently treats any non-'mainnet' value as testnet; update
getUsdcIssuer to validate STELLAR_NETWORK explicitly (accept only 'mainnet' or
'testnet') and fail fast on invalid values by throwing an Error (or at minimum
logging a loud warning and throwing) so misconfigured environments don't
silently use TESTNET_USDC_ISSUER; reference STELLAR_NETWORK and the existing
symbols NEXT_PUBLIC_USDC_ISSUER_MAINNET, MAINNET_USDC_ISSUER,
NEXT_PUBLIC_USDC_ISSUER_TESTNET, TESTNET_USDC_ISSUER and implement the guard at
the start of getUsdcIssuer.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/hooks/useUserRole.tsx (1)

28-46: Reset host flags when userId is missing.
Line 43 only sets role to guest but keeps prior hostStatus, canAccessHostDashboard, and hasProperties, which can surface host UI for an invalid user. Reset to safe defaults here.

Proposed fix
-        setRoleInfo((prev: RoleInfo) => ({ ...prev, role: 'guest' }));
+        setRoleInfo({
+          role: 'guest',
+          hostStatus: undefined,
+          canAccessHostDashboard: false,
+          hasProperties: false,
+        });
🤖 Fix all issues with AI agents
In `@apps/web/src/app/layout.tsx`:
- Around line 16-17: The page metadata currently sets title/description in
Spanish while the root HTML element uses lang="en"; update either the HTML lang
attribute or the metadata description to match language intent—e.g., change
lang="en" to lang="es" if you want Spanish site-wide (modify the root <html
lang> declaration in layout.tsx) or translate the description value ('Alquileres
con USDC en la red Stellar') into English to keep lang="en" consistent (update
the exported metadata.description).

In `@apps/web/src/constants/menu-items.ts`:
- Around line 63-67: The file contains unresolved Git conflict markers around
the menu exports; remove the conflict markers and resolve to the intended
variant for TENANT_MENU_ITEMS, HOST_MENU_ITEMS and DUAL_MENU_ITEMS (either keep
the HEAD shorthand exports that set them to [...GUEST_MENU_ITEMS] or restore the
role-specific arrays from origin/main), then ensure the final code exports valid
MenuItem[] constants and that GUEST_MENU_ITEMS is imported/defined; also remove
any leftover <<<<<<<, =======, or >>>>>>> tokens so the file compiles cleanly.

In `@apps/web/src/hooks/useUserRole.tsx`:
- Around line 4-10: Remove all merge conflict markers (<<<<<<<, =======,
>>>>>>>) in useUserRole.tsx and choose the correct implementation for
useUserRole; ensure you keep the logic that derives userId as user.publicKey ||
user.id (do not add || 'unknown') and remove any duplicated or competing blocks.
Verify imports for profileAPI and types RoleInfo/UserRole remain single, correct
statements and that the hook implementation (useUserRole) is consistent—then run
TypeScript build to confirm no leftover conflict markers or duplicate
definitions.
🧹 Nitpick comments (1)
apps/web/src/app/layout.tsx (1)

6-6: Consider using English for code comments.

The comment is in Spanish ("CORRECCIÓN: La ruta es..."). For maintainability and accessibility to international contributors, consider using English for inline comments.

Comment on lines 63 to 67
<<<<<<< HEAD
export const TENANT_MENU_ITEMS: MenuItem[] = [...GUEST_MENU_ITEMS];
export const HOST_MENU_ITEMS: MenuItem[] = [...GUEST_MENU_ITEMS];
export const DUAL_MENU_ITEMS: MenuItem[] = [...GUEST_MENU_ITEMS];
=======
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Unresolved merge conflict markers in code.

The file contains merge conflict markers (<<<<<<< HEAD, =======, >>>>>>> origin/main) that will cause syntax errors. These must be resolved before merging.

Based on the structure, the HEAD version (lines 64-66) consolidates all role menus to share GUEST_MENU_ITEMS, while origin/main (lines 68-210) has distinct role-specific menus. Determine the intended behavior and remove the conflict markers.

🤖 Prompt for AI Agents
In `@apps/web/src/constants/menu-items.ts` around lines 63 - 67, The file contains
unresolved Git conflict markers around the menu exports; remove the conflict
markers and resolve to the intended variant for TENANT_MENU_ITEMS,
HOST_MENU_ITEMS and DUAL_MENU_ITEMS (either keep the HEAD shorthand exports that
set them to [...GUEST_MENU_ITEMS] or restore the role-specific arrays from
origin/main), then ensure the final code exports valid MenuItem[] constants and
that GUEST_MENU_ITEMS is imported/defined; also remove any leftover <<<<<<<,
=======, or >>>>>>> tokens so the file compiles cleanly.

Comment on lines 4 to 10
<<<<<<< HEAD
// @ts-ignore: Alias resolution issue
=======
>>>>>>> origin/main
import { profileAPI } from '~/services/api';
// @ts-ignore: Alias resolution issue
import type { RoleInfo, UserRole } from '~/types/roles';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Resolve merge conflict markers before merging.
<<<<<<<, =======, >>>>>>> are still present (Line 4, Line 52, Line 125), which will break compilation and leave two competing implementations. Resolve the conflicts and ensure the chosen branch keeps userId derived from user.publicKey || user.id (avoid the || 'unknown' fallback on Line 57).

Also applies to: 52-60, 125-129

🤖 Prompt for AI Agents
In `@apps/web/src/hooks/useUserRole.tsx` around lines 4 - 10, Remove all merge
conflict markers (<<<<<<<, =======, >>>>>>>) in useUserRole.tsx and choose the
correct implementation for useUserRole; ensure you keep the logic that derives
userId as user.publicKey || user.id (do not add || 'unknown') and remove any
duplicated or competing blocks. Verify imports for profileAPI and types
RoleInfo/UserRole remain single, correct statements and that the hook
implementation (useUserRole) is consistent—then run TypeScript build to confirm
no leftover conflict markers or duplicate definitions.

const [searchQuery, setSearchQuery] = useState('');

return (
/* CORRECCIÓN: Se cambió 64px por 56px para coincidir con la altura real del Navbar (h-14) */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this comment

return [sorted[0]?.price || 0, sorted.at(-1)?.price || 0] as [number, number];
}, []);

// Alias para evitar el error de IntrinsicAttributes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be in english please

export const metadata: Metadata = {
title: 'StellaRent',
description: 'Plataforma de alquiler de propiedades',
title: 'Stellar Rent',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variables in english

'use client';

import { useEffect, useState } from 'react';
<<<<<<< HEAD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a merge error

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/hooks/auth/use-auth.tsx (1)

67-96: ⚠️ Potential issue | 🟡 Minor

Potential race condition: both effects set isLoading(false) on mount.

initSDK (lines 67-96) and restoreSession (lines 98-121) both run on mount and both call setIsLoading(false) in their finally blocks. If initSDK completes first and sets isLoading(false), then restoreSession may later set it to false again (harmless) or vice versa. However, if either fails or takes longer, the loading state may become inconsistent.

Consider consolidating initialization logic or coordinating these effects to ensure loading state accurately reflects when both operations complete.

Also applies to: 98-121

🤖 Fix all issues with AI agents
In `@apps/web/src/app/invitations/page.tsx`:
- Line 349: The backdrop div that currently uses onClick={onClose} is not
keyboard accessible; update the element that renders the backdrop (the element
with className "absolute inset-0 bg-black/60" and using onClose) to support
keyboard interaction by either replacing it with a focusable element (e.g., a
styled button) or adding role="button", tabIndex={0}, an onKeyDown handler that
triggers onClose when Escape or Enter/Space is pressed, and an accessible label
(aria-label or aria-hidden as appropriate); ensure you still call the existing
onClose function so keyboard users can dismiss the drawer.

In `@apps/web/src/app/layout.tsx`:
- Around line 38-41: RightSidebar is positioned fixed with width w-12 so the
<main> content (the element rendering {children}) can slide underneath it; add
right padding or margin equal to the sidebar width (e.g., pr-12 or mr-12 /
paddingRight: '3rem') to the main container's className or style in layout.tsx
to reserve space and prevent overlap, and ensure any responsive variants match
the RightSidebar's visibility if it changes.

In `@apps/web/src/app/search/property/page.tsx`:
- Around line 37-40: The totals and fee variables (subtotal, cleaningFee,
serviceFee, total) are computed even when nights === 0 which shows misleading
fees; update the logic in the component so cleaningFee and serviceFee are zero
(or the entire breakdown is hidden) until valid dates/nights > 0 — e.g., set
cleaningFee = nights > 0 ? 150 : 0 and serviceFee = nights > 0 ? 100 : 0,
compute subtotal only when property && nights > 0, and/or render the price
breakdown conditionally based on nights > 0; apply the same guard to the other
block referenced (lines with the secondary total computation).

In `@apps/web/src/lib/stellar.ts`:
- Around line 71-79: The call to window.freighterApi.signTransaction returns an
object (signedTransaction) with a signedTxXdr field, but submitTransaction
expects a string XDR; update the code that calls submitTransaction (after
window.freighterApi.signTransaction) to pass signedTransaction.signedTxXdr
instead of the whole signedTransaction object so submitTransaction receives the
correct string input (locate the sign/submit flow using
window.freighterApi.signTransaction, the signedTransaction variable, and the
submitTransaction function).
- Around line 46-51: The code in submitTransaction currently constructs a
Transaction directly from the XDR string; replace that with the documented
parser: call TransactionBuilder.fromXDR(signedTransactionXDR,
NETWORK_PASSPHRASE) to produce the transaction object before passing it to
server.submitTransaction. Update the creation of transactionToSubmit (or
equivalent variable) to use TransactionBuilder.fromXDR instead of new
Transaction so the signedTransactionXDR is parsed with the supported SDK API.
🧹 Nitpick comments (9)
apps/web/src/app/search/page.tsx (3)

19-20: Consider moving PAGE_SIZE outside the component.

PAGE_SIZE is a constant that doesn't depend on props or state. Defining it inside the component recreates the variable on every render. Hoisting it to module scope improves clarity and avoids unnecessary work.

♻️ Suggested refactor
 import { SortOptions } from '~/components/search/SortOptions';
+
+const PAGE_SIZE = 3;
 
 const PropertyMap = dynamic(() => import('@/components/search/Map'), {
   ssr: false,
 });
 
 export default function SearchPage() {
   const [page, setPage] = useState(1);
-  const PAGE_SIZE = 3;
   const [sortOrder, setSortOrder] = useState('price_asc');

29-33: Static data creates new references on every render.

mapCenter and mapMarkers are hardcoded values but defined inline, so they produce new array/object references each render. Since they're passed as props to FilterSidebar and PropertyMap, this can trigger unnecessary child re-renders.

Move them to module scope or wrap them in useMemo with an empty dependency array.

♻️ Suggested refactor (module scope)
+const MAP_CENTER: LatLngTuple = [-34.61, -58.39];
+const MAP_MARKERS: { position: LatLngTuple; title: string }[] = [
+  { position: [-34.61, -58.39], title: 'Modern Apartment with Kitchen' },
+  { position: [-34.6, -58.37], title: 'Cozy Studio Apartment' },
+];
+
 export default function SearchPage() {
   const [page, setPage] = useState(1);
   const PAGE_SIZE = 3;
   const [sortOrder, setSortOrder] = useState('price_asc');
   // ...
-  const mapCenter: LatLngTuple = [-34.61, -58.39];
-  const mapMarkers: { position: LatLngTuple; title: string }[] = [
-    { position: [-34.61, -58.39], title: 'Modern Apartment with Kitchen' },
-    { position: [-34.6, -58.37], title: 'Cozy Studio Apartment' },
-  ];

Then update usages to MAP_CENTER and MAP_MARKERS.


59-68: Consider using a switch statement for sorting logic.

The current implementation uses multiple independent if statements, so all conditions are evaluated even after one matches. A switch or if-else chain would short-circuit after the first match.

♻️ Suggested refactor
-    if (sortOrder === 'price_asc') result.sort((a, b) => a.price - b.price);
-    if (sortOrder === 'price_desc') result.sort((a, b) => b.price - a.price);
-    if (sortOrder === 'rating') result.sort((a, b) => b.rating - a.rating);
-    if (sortOrder === 'distance') {
-      result.sort((a, b) => {
-        const distA = Number.parseFloat(a.distance);
-        const distB = Number.parseFloat(b.distance);
-        return distA - distB;
-      });
-    }
+    switch (sortOrder) {
+      case 'price_asc':
+        result.sort((a, b) => a.price - b.price);
+        break;
+      case 'price_desc':
+        result.sort((a, b) => b.price - a.price);
+        break;
+      case 'rating':
+        result.sort((a, b) => b.rating - a.rating);
+        break;
+      case 'distance':
+        result.sort((a, b) => {
+          const distA = Number.parseFloat(a.distance);
+          const distB = Number.parseFloat(b.distance);
+          return distA - distB;
+        });
+        break;
+    }
apps/web/src/app/search/property/page.tsx (1)

17-17: Avoid global image fallback on single failure.

Any single image error flips imageError and replaces the full gallery. Also, once set, it may persist if propertyId changes. Consider tracking per-image failures and resetting when the property changes to keep healthy images visible.

♻️ Possible refactor
-const [imageError, setImageError] = useState(false);
+const [imageErrors, setImageErrors] = useState<Record<number, boolean>>({});

 useEffect(() => {
   if (propertyId) {
+    setImageErrors({});
     const match = MOCK_PROPERTIES.find((p) => p.id === propertyId);
     setProperty(match || null);
   }
 }, [propertyId]);

 ...
-<Image
+{imageErrors[index] ? (
+  <div className="w-full h-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center">
+    <p className="text-muted-foreground text-xs">Image not available</p>
+  </div>
+) : (
+  <Image
     width={300}
     height={300}
     src={img}
     alt={`${property.title} ${index + 1}`}
     className="w-full h-full object-cover"
-    onError={() => setImageError(true)}
+    onError={() => setImageErrors((prev) => ({ ...prev, [index]: true }))}
-/>
+  />
+)}

Also applies to: 79-86

apps/web/src/lib/stellar.ts (1)

92-99: Silently returning '0' may mask configuration errors.

Catching the getUSDCAsset() error and returning '0' hides misconfigurations from the caller. Consider propagating or logging more prominently so balance-fetch failures due to config issues are distinguishable from accounts with zero balance.

apps/web/src/lib/stellar-social-sdk.ts (2)

1-2: Fragile relative import path with @ts-ignore.

The import '../../../../index' is brittle and relies on exact directory structure. If the project structure changes, this breaks silently (suppressed by @ts-ignore). Consider using a path alias or package reference if possible.


8-14: Consider aligning these type definitions with the SDK or clearly documenting their purpose.

The local AuthMethod (string union), SocialAuthConfig (with clientId, method), and other types in this file differ structurally from the SDK's actual types in apps/web/stellar-social-sdk/src/types/index.ts. While the file comment indicates these are "manually defined types to prevent TS2305 errors," they are not imported anywhere in the codebase. The application correctly uses types from ~/types/auth and proper SDK initialization. However, exporting unused/divergent types could confuse future maintainers. Either align these exports with the SDK types, remove them if unnecessary, or add explicit documentation clarifying they are app-specific workarounds unrelated to SDK types.

apps/web/src/hooks/auth/use-auth.tsx (1)

151-174: Missing handleGoogleAuthComplete in useEffect dependency array.

The setupGoogleOAuth effect assigns handleGoogleAuthComplete to window.handleGoogleCredential and passes it to google.accounts.id.initialize. However, handleGoogleAuthComplete is not listed in the effect's dependency array [sdk]. If handleGoogleAuthComplete reference changes, the stale callback remains registered.

Since handleGoogleAuthComplete is wrapped in useCallback with an empty dependency array (line 176), this is unlikely to cause issues in practice, but including it in the deps array ensures correctness.

Proposed fix
-  }, [sdk]);
+  }, [sdk, handleGoogleAuthComplete]);
apps/web/src/app/invitations/page.tsx (1)

319-319: Avoid any types for component props.

PaginationControls (line 319) and MobileMenuDrawer (line 345) use any for their props, which disables type checking. Consider defining proper interfaces for these internal components.

Proposed types
interface PaginationControlsProps {
  className?: string;
  currentPage: number;
  totalPages: number;
  onPrevious: () => void;
  onNext: () => void;
}

interface MobileMenuDrawerProps {
  isOpen: boolean;
  onClose: () => void;
  menuItems: MenuItem[];
}

Also applies to: 345-345

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/types/index.ts (1)

1-1: ⚠️ Potential issue | 🟠 Major

Duplicate Notification type creates a naming collision and type fragmentation across the codebase. export * from './shared' at line 1 re-exports Notification from shared.ts, but this file also defines its own Notification interface at lines 85-102 with incompatible shapes. The local definition shadows the re-export, causing different parts of the codebase to use different Notification types:

  • apps/web/src/types/shared.ts: isRead: boolean, createdAt: string, userId: string (required)
  • apps/web/src/types/index.ts: read: boolean, timestamp: Date, optional userId in metadata

Files importing from @/types get the index.ts version, while files importing directly from @/types/shared get the shared.ts version. This has led to NotificationSystem.tsx duplicating the interface definition locally as a workaround. Consolidate to a single Notification type with all required fields and ensure consistent usage across the codebase.

🤖 Fix all issues with AI agents
In `@apps/web/src/app/booking/page.tsx`:
- Around line 101-112: The booking result mapping is using the wrong property
and not validating optionals: replace bookingResult.bookingId with
bookingResult.id (the Booking.id field returned by createBooking), remove the
unsafe "as any" cast by typing the response to the expected API/Booking shape
(or narrow it before use), and validate that bookingResult.escrowAddress exists
before passing it into setCurrentBookingData (or provide a safe fallback / abort
with an error toast if missing). Update uses of bookingResult, createBooking,
setCurrentBookingData and currentBookingData accordingly to ensure the payment
flow receives a valid id and escrowAddress.

In `@apps/web/src/app/dashboard/host-dashboard/components/AddPropertyModal.tsx`:
- Around line 228-231: The bathrooms handler currently uses Number.parseInt
which truncates decimal values; update the setNewProperty call that sets
bathrooms (the callback passed to setNewProperty) to parse the input with
Number.parseFloat (or Number) instead of Number.parseInt so values like "1.5"
and "2.5" are preserved (change the bathrooms: Number.parseInt(e.target.value)
line to use Number.parseFloat(e.target.value) or Number(e.target.value)).

In `@apps/web/src/app/dashboard/host-dashboard/page.tsx`:
- Around line 152-158: handleUploadAvatar currently creates blob URLs with
URL.createObjectURL but never revokes them, leaking memory on repeated uploads;
update handleUploadAvatar to revoke the previous blob URL before
creating/setting a new one (track the previous avatar blob URL from state or a
ref and call URL.revokeObjectURL(prevBlob) when replacing it) and add a cleanup
in the component unmount (useEffect cleanup) to revoke any remaining blob URL;
reference the handleUploadAvatar function and the setUser state updater when
implementing this fix.

In `@apps/web/src/app/property/`[id]/page.tsx:
- Around line 24-32: The component PropertySearchPage is incorrectly using
useSearchParams() to read the dynamic route id; replace useSearchParams with
useParams(), get propertyId from the returned params object (e.g. const { id:
propertyId } = useParams()), update any references and the useMemo dependency to
[propertyId], and keep the existing lookup (PROPERTIES.find((p) => p.id ===
propertyId) || PROPERTIES[0]) so the path segment id is used instead of the
query string.

In `@apps/web/src/hooks/auth/use-auth.tsx`:
- Around line 64-69: The logout function calls
localStorage.removeItem('stellar_social_user') directly which breaks SSR; guard
the storage access in logout by checking for a browser environment (e.g. typeof
window !== 'undefined' or checking globalThis.localStorage) before calling
localStorage.removeItem, leaving setUser(null), setAccount(null), and
setAuthMethod(null) unchanged so state is cleared server-side-safe.
- Around line 79-83: The placeholder no-op auth methods (loginWithGoogle,
loginWithFreighter, getBalance, sendPayment) can silently fail for callers;
replace each empty async function with a development-visible failure: either
throw a descriptive Error like "loginWithGoogle not implemented" (so callers
immediately get a failure) or at minimum call console.warn with the same message
and then throw in non-production (check process.env.NODE_ENV !== 'production').
Update the implementations for loginWithGoogle, loginWithFreighter, getBalance,
and sendPayment accordingly so they produce an obvious runtime error/warning
rather than returning empty values.

In `@apps/web/src/hooks/useDashboard.ts`:
- Around line 169-177: The stub action methods cancelBooking, updateProfile and
exportTransactions currently only log and return undefined which breaks callers
(e.g., TenantDashboard.handleConfirmCancel expects a boolean success); update
these functions to return explicit, relevant values (e.g., cancelBooking should
return a boolean or Promise<boolean> indicating success/failure, updateProfile
should return the updated profile object or boolean/Promise<boolean>, and
exportTransactions should return a success indicator or Promise) and ensure they
resolve/reject consistently so callers can rely on their return values instead
of undefined.

In `@apps/web/src/lib/stellar-social-sdk.ts`:
- Around line 10-18: The module currently initializes the SDK at load time by
calling getSDK(), so StellarSocialSDK becomes null during SSR/build and never
updates after hydration; change to lazy initialization by replacing the exported
constant with a function or getter that resolves RootSDK at runtime (e.g.,
export a getStellarSocialSDK or a lazy getter) and have it call getSDK() (or
inline its logic) when first invoked, ensuring you reference getSDK,
StellarSocialSDK, and RootSDK in the implementation so the runtime window check
is executed on-demand rather than at module-evaluation time.
- Around line 21-27: Update the AuthMethod union to match actual usage by
replacing/merging its values with the canonical set used across the app (add
'freighter' and remove unused 'apple'|'facebook'|'wallet') so the exported
AuthMethod type aligns with types/auth.ts; also remove the unused
SocialAuthConfig interface (dead code) from
apps/web/src/lib/stellar-social-sdk.ts to avoid stale exports and keep typings
consistent.
🧹 Nitpick comments (14)
apps/web/next.config.js (1)

23-23: Unused _isServer parameter can be removed.

The _isServer is destructured but never used in the function body. If this parameter isn't needed, simplify the signature:

✨ Suggested cleanup
-  webpack: (config, { _isServer }) => {
+  webpack: (config) => {

If you plan to use isServer in the future for conditional logic (e.g., server-only aliases), keep it but remove the underscore prefix when you start using it.

apps/web/src/app/property/[id]/page.tsx (2)

29-32: Fallback to first property may mask errors.

When a property isn't found, the code silently falls back to PROPERTIES[0]. This could confuse users who access an invalid property ID, as they'll see unrelated content instead of an error or 404 page.

Consider showing an appropriate error state or redirecting to a 404 page when the property is not found.


88-95: Associate label with input for accessibility.

The label element is not programmatically associated with the input, which may affect screen reader users.

♿ Proposed fix
-              <label className="text-sm font-medium text-gray-400">Nights to stay</label>
+              <label htmlFor="nights-input" className="text-sm font-medium text-gray-400">Nights to stay</label>
               <input
+                id="nights-input"
                 type="number"
                 min="0"
apps/web/src/app/booking/page.tsx (2)

72-84: User must re-submit after wallet connection.

After a successful wallet connection on line 75, the function returns without proceeding with the booking. The user will need to click the submit button again. Consider either:

  1. Showing a toast like toast.success('Wallet connected! Please submit again.') to guide the user, or
  2. Automatically proceeding with the booking after successful connection
💡 Option 1: Add user guidance toast
       await connect();
       toast.dismiss('connect-wallet');
+      toast.success('Wallet connected! Please submit again to continue.');
       return;

90-99: Type safety bypassed with as any cast for userId.

The ...({ userId: publicKey } as any) pattern circumvents TypeScript's type checking. Based on the relevant snippet, BookingFormData is the expected type for createBooking. If userId is a required field, consider updating the BookingFormData type definition to include it.

♻️ Suggested approach

Update the BookingFormData type in your types file to include userId:

interface BookingFormData {
  propertyId: string;
  userId: string; // Add this field
  dates: { from: Date; to: Date };
  guests: number;
  total: number;
  deposit: number;
}

Then remove the cast:

 const response = await bookingAPI.createBooking({
   propertyId: data.property.id,
-  // Using as any for userId if it's not in the strict BookingFormData type yet
-  ...({ userId: publicKey } as any),
+  userId: publicKey,
   dates: data.dates,
   guests: data.guests,
   total: data.totalAmount,
   deposit: data.depositAmount,
 });
apps/web/src/app/dashboard/host-dashboard/page.tsx (2)

161-165: Prefer functional state update for date toggling.

This avoids stale reads if multiple selections happen before React flushes state.

♻️ Suggested refactor
-    const dateStr = date.toISOString().split('T')[0];
-    const newSelectedDates = new Set(selectedDates);
-    if (newSelectedDates.has(dateStr)) newSelectedDates.delete(dateStr);
-    else newSelectedDates.add(dateStr);
-    setSelectedDates(newSelectedDates);
+    const dateStr = date.toISOString().split('T')[0];
+    setSelectedDates((prev) => {
+      const next = new Set(prev);
+      if (next.has(dateStr)) next.delete(dateStr);
+      else next.add(dateStr);
+      return next;
+    });

238-249: Use functional updates for property mutations.

These updates derive from the previous state, so the functional form is safer under concurrent updates.

♻️ Suggested refactor
-              onAddProperty={(p) =>
-                setProperties([
-                  ...properties,
-                  { ...p, id: Date.now(), rating: 0, reviews: 0, bookings: 0, earnings: 0 },
-                ])
-              }
-              onUpdateProperty={(id, upds) =>
-                setProperties(properties.map((p) => (p.id === id ? { ...p, ...upds } : p)))
-              }
-              onDeleteProperty={(id) => setProperties(properties.filter((p) => p.id !== id))}
-              onToggleStatus={(id, status) =>
-                setProperties(properties.map((p) => (p.id === id ? { ...p, status } : p)))
-              }
+              onAddProperty={(p) =>
+                setProperties((prev) => [
+                  ...prev,
+                  { ...p, id: Date.now(), rating: 0, reviews: 0, bookings: 0, earnings: 0 },
+                ])
+              }
+              onUpdateProperty={(id, upds) =>
+                setProperties((prev) => prev.map((p) => (p.id === id ? { ...p, ...upds } : p)))
+              }
+              onDeleteProperty={(id) =>
+                setProperties((prev) => prev.filter((p) => p.id !== id))
+              }
+              onToggleStatus={(id, status) =>
+                setProperties((prev) => prev.map((p) => (p.id === id ? { ...p, status } : p)))
+              }
apps/web/src/lib/stellar.ts (1)

135-141: Consider using proper Horizon balance types instead of as any.

The as any cast bypasses type safety. The Stellar SDK provides Horizon.HorizonApi.BalanceLine types that can be narrowed properly.

♻️ Proposed type-safe alternative
     const usdcBalance = account.balances.find((balance) => {
       if (balance.asset_type === 'credit_alphanum4' || balance.asset_type === 'credit_alphanum12') {
-        const b = balance as any;
-        return b.asset_code === asset.code && b.asset_issuer === asset.issuer;
+        return (
+          'asset_code' in balance &&
+          'asset_issuer' in balance &&
+          balance.asset_code === asset.code &&
+          balance.asset_issuer === asset.issuer
+        );
       }
       return false;
     });
apps/web/src/app/invitations/page.tsx (1)

319-319: Define proper TypeScript interfaces for component props.

Using any for component props (PaginationControls, MobileMenuDrawer) loses type safety and IDE support. Consider defining explicit interfaces.

♻️ Proposed type definitions
interface PaginationControlsProps {
  className?: string;
  currentPage: number;
  totalPages: number;
  onPrevious: () => void;
  onNext: () => void;
}

interface MobileMenuDrawerProps {
  isOpen: boolean;
  onClose: () => void;
  menuItems: MenuItem[];
}

Also applies to: 345-345

apps/web/src/hooks/useDashboard.ts (1)

18-18: Define a proper return type instead of any.

The hook returns any, losing all type safety for consumers. Define an interface for the return value to enable proper TypeScript checking.

♻️ Proposed interface
interface UseDashboardReturn {
  bookings: DashboardBooking[];
  user: UserProfile | null;
  transactions: Transaction[];
  stats: DashboardStats | null;
  isLoadingBookings: boolean;
  isLoadingProfile: boolean;
  isLoadingTransactions: boolean;
  isLoadingStats: boolean;
  error: string | null;
  cancelBooking: (id: string | number) => Promise<void>;
  updateProfile: (data: Partial<UserProfile>) => Promise<void>;
  exportTransactions: () => void;
  refetchAll: () => Promise<void>;
  isAuthenticated: boolean;
  walletBalance: number;
  pendingTransactions: Transaction[];
}
apps/web/src/app/tenant-dashboard/page.tsx (3)

126-128: Replace confirm() with a custom modal for better UX.

Using the browser's native confirm() dialog blocks the UI thread and provides poor user experience. Consider using a custom confirmation modal consistent with the app's design system (similar to CancelModal).


64-64: Excessive as any casts indicate type mismatches.

Multiple as any casts throughout the component suggest interface drift between useDashboard return values and component props. Consider aligning types properly rather than casting to avoid runtime errors from unexpected data shapes.

Also applies to: 281-295


91-92: Log error details before showing generic messages.

The _error variables are caught but discarded. For debugging, consider logging the actual error before showing the generic toast message.

Example
-    } catch (_error) {
+    } catch (error) {
+      console.error('Cancel booking failed:', error);
       showToast('An error occurred while cancelling the booking', 'error');

Also applies to: 104-105, 119-120, 135-136

apps/web/src/types/index.ts (1)

115-118: Status mapping has a type gap for non-matching values.

When booking.status is 'ongoing', 'completed', or 'cancelled', the cast as any bypasses type checking. However, LegacyBooking.status only allows 'upcoming' | 'ongoing' | 'completed' | 'cancelled', so this works correctly at runtime. Consider explicit mapping for clarity.

♻️ Explicit status mapping
     status:
-      booking.status === 'pending' || booking.status === 'confirmed'
-        ? 'upcoming'
-        : (booking.status as any),
+      booking.status === 'pending' || booking.status === 'confirmed'
+        ? 'upcoming'
+        : booking.status, // 'ongoing' | 'completed' | 'cancelled' are compatible

Comment on lines +228 to +231
setNewProperty((prev) => ({
...prev,
bathrooms: Number.parseInt(e.target.value),
}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "AddPropertyModal.tsx" | head -5

Repository: Stellar-Rent/stellar-rent

Length of output: 144


🏁 Script executed:

wc -l ./apps/web/src/app/dashboard/host-dashboard/components/AddPropertyModal.tsx

Repository: Stellar-Rent/stellar-rent

Length of output: 148


🏁 Script executed:

cat -n ./apps/web/src/app/dashboard/host-dashboard/components/AddPropertyModal.tsx | sed -n '210,245p'

Repository: Stellar-Rent/stellar-rent

Length of output: 1650


🏁 Script executed:

cat -n ./apps/web/src/app/dashboard/host-dashboard/components/AddPropertyModal.tsx | sed -n '1,50p'

Repository: Stellar-Rent/stellar-rent

Length of output: 1441


Use parseFloat instead of parseInt to preserve decimal bathroom values.

The bathrooms select includes values like 1.5, 2.5, etc., but Number.parseInt truncates them to integers. Change to Number.parseFloat or Number to preserve decimal values.

🛠️ Suggested fix
-                        bathrooms: Number.parseInt(e.target.value),
+                        bathrooms: Number.parseFloat(e.target.value),
📝 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.

Suggested change
setNewProperty((prev) => ({
...prev,
bathrooms: Number.parseInt(e.target.value),
}))
setNewProperty((prev) => ({
...prev,
bathrooms: Number.parseFloat(e.target.value),
}))
🤖 Prompt for AI Agents
In `@apps/web/src/app/dashboard/host-dashboard/components/AddPropertyModal.tsx`
around lines 228 - 231, The bathrooms handler currently uses Number.parseInt
which truncates decimal values; update the setNewProperty call that sets
bathrooms (the callback passed to setNewProperty) to parse the input with
Number.parseFloat (or Number) instead of Number.parseInt so values like "1.5"
and "2.5" are preserved (change the bathrooms: Number.parseInt(e.target.value)
line to use Number.parseFloat(e.target.value) or Number(e.target.value)).

Comment on lines +24 to +32
const PropertySearchPage = () => {
const searchParams = useSearchParams();
const propertyId = searchParams.get('id');
const [nights, setNights] = useState(0);

const property = useMemo(
() => PROPERTIES.find((p) => p.id === propertyId) || PROPERTIES[0],
[propertyId]
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Use useParams instead of useSearchParams for dynamic route segments.

The file path apps/web/src/app/property/[id]/page.tsx indicates a dynamic route where id is a path segment. In Next.js App Router, dynamic segments should be accessed via useParams(), not useSearchParams().

With the current implementation:

  • URL /property/123propertyId will be null (the id is in the path, not query string)
  • URL /property/abc?id=123propertyId will be "123" (reading from query string, ignoring path)
🐛 Proposed fix
-import { useSearchParams } from 'next/navigation';
+import { useParams } from 'next/navigation';
-import { useMemo, useState } from 'react';
+import { useState } from 'react';

 const PropertySearchPage = () => {
-  const searchParams = useSearchParams();
-  const propertyId = searchParams.get('id');
+  const params = useParams();
+  const propertyId = params.id as string | undefined;
   const [nights, setNights] = useState(0);

-  const property = useMemo(
-    () => PROPERTIES.find((p) => p.id === propertyId) || PROPERTIES[0],
-    [propertyId]
-  );
+  const property = PROPERTIES.find((p) => p.id === propertyId) || PROPERTIES[0];
🤖 Prompt for AI Agents
In `@apps/web/src/app/property/`[id]/page.tsx around lines 24 - 32, The component
PropertySearchPage is incorrectly using useSearchParams() to read the dynamic
route id; replace useSearchParams with useParams(), get propertyId from the
returned params object (e.g. const { id: propertyId } = useParams()), update any
references and the useMemo dependency to [propertyId], and keep the existing
lookup (PROPERTIES.find((p) => p.id === propertyId) || PROPERTIES[0]) so the
path segment id is used instead of the query string.

Comment on lines +64 to +69
const logout = () => {
setUser(null);
setAccount(null);
setAuthMethod(null);

// Limpiar localStorage
clearStorage();

// Revocar acceso de Google si estaba autenticado con Google
if (authMethod === 'google' && window.google?.accounts?.id) {
window.google.accounts.id.disableAutoSelect();
}

toast.success('Logged out');
console.log('✅ Logged out');
}, [authMethod]);

// Obtener balance
const getBalance = useCallback(async (): Promise<BalanceInfo[]> => {
if (!account) {
console.warn('No account available for balance check');
return [];
}

try {
const balances = await account.getBalance();
return balances;
} catch (error) {
console.error('Error fetching balance:', error);
return [];
}
}, [account]);

// Enviar pago
const sendPayment = useCallback(
async (to: string, amount: string, memo?: string): Promise<string> => {
if (!account) {
throw new Error('No active account');
}

const toastId = toast.loading('Sending payment...');

try {
const txHash = await account.sendPayment(to, amount, undefined, memo);
toast.success('Payment sent successfully', { id: toastId });
return txHash;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to send payment';
toast.error(errorMessage, { id: toastId });
throw error;
}
},
[account]
);

const isAuthenticated = !!user && !!user.publicKey;
localStorage.removeItem('stellar_social_user');
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard localStorage access for SSR safety.

The logout function accesses localStorage without checking if window is defined, which will throw during server-side rendering.

🛡️ Proposed fix
   const logout = () => {
     setUser(null);
     setAccount(null);
     setAuthMethod(null);
-    localStorage.removeItem('stellar_social_user');
+    if (typeof window !== 'undefined') {
+      localStorage.removeItem('stellar_social_user');
+    }
   };
📝 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.

Suggested change
const logout = () => {
setUser(null);
setAccount(null);
setAuthMethod(null);
// Limpiar localStorage
clearStorage();
// Revocar acceso de Google si estaba autenticado con Google
if (authMethod === 'google' && window.google?.accounts?.id) {
window.google.accounts.id.disableAutoSelect();
}
toast.success('Logged out');
console.log('✅ Logged out');
}, [authMethod]);
// Obtener balance
const getBalance = useCallback(async (): Promise<BalanceInfo[]> => {
if (!account) {
console.warn('No account available for balance check');
return [];
}
try {
const balances = await account.getBalance();
return balances;
} catch (error) {
console.error('Error fetching balance:', error);
return [];
}
}, [account]);
// Enviar pago
const sendPayment = useCallback(
async (to: string, amount: string, memo?: string): Promise<string> => {
if (!account) {
throw new Error('No active account');
}
const toastId = toast.loading('Sending payment...');
try {
const txHash = await account.sendPayment(to, amount, undefined, memo);
toast.success('Payment sent successfully', { id: toastId });
return txHash;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to send payment';
toast.error(errorMessage, { id: toastId });
throw error;
}
},
[account]
);
const isAuthenticated = !!user && !!user.publicKey;
localStorage.removeItem('stellar_social_user');
};
const logout = () => {
setUser(null);
setAccount(null);
setAuthMethod(null);
if (typeof window !== 'undefined') {
localStorage.removeItem('stellar_social_user');
}
};
🤖 Prompt for AI Agents
In `@apps/web/src/hooks/auth/use-auth.tsx` around lines 64 - 69, The logout
function calls localStorage.removeItem('stellar_social_user') directly which
breaks SSR; guard the storage access in logout by checking for a browser
environment (e.g. typeof window !== 'undefined' or checking
globalThis.localStorage) before calling localStorage.removeItem, leaving
setUser(null), setAccount(null), and setAuthMethod(null) unchanged so state is
cleared server-side-safe.

Comment on lines +79 to +83
loginWithGoogle: async () => {},
loginWithFreighter: async () => {},
logout,
getBalance,
sendPayment,
getBalance: async () => [],
sendPayment: async () => '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

No-op authentication functions may cause silent failures.

loginWithGoogle, loginWithFreighter, getBalance, and sendPayment are placeholder no-ops. Consumers calling these will receive empty results without errors, potentially masking integration issues. Consider adding console warnings or throwing "not implemented" errors during development.

🔧 Suggested improvement
-        loginWithGoogle: async () => {},
-        loginWithFreighter: async () => {},
+        loginWithGoogle: async () => {
+          console.warn('loginWithGoogle is not yet implemented');
+        },
+        loginWithFreighter: async () => {
+          console.warn('loginWithFreighter is not yet implemented');
+        },
📝 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.

Suggested change
loginWithGoogle: async () => {},
loginWithFreighter: async () => {},
logout,
getBalance,
sendPayment,
getBalance: async () => [],
sendPayment: async () => '',
loginWithGoogle: async () => {
console.warn('loginWithGoogle is not yet implemented');
},
loginWithFreighter: async () => {
console.warn('loginWithFreighter is not yet implemented');
},
logout,
getBalance: async () => [],
sendPayment: async () => '',
🤖 Prompt for AI Agents
In `@apps/web/src/hooks/auth/use-auth.tsx` around lines 79 - 83, The placeholder
no-op auth methods (loginWithGoogle, loginWithFreighter, getBalance,
sendPayment) can silently fail for callers; replace each empty async function
with a development-visible failure: either throw a descriptive Error like
"loginWithGoogle not implemented" (so callers immediately get a failure) or at
minimum call console.warn with the same message and then throw in non-production
(check process.env.NODE_ENV !== 'production'). Update the implementations for
loginWithGoogle, loginWithFreighter, getBalance, and sendPayment accordingly so
they produce an obvious runtime error/warning rather than returning empty
values.

Comment on lines 169 to 177
cancelBooking: async (id: any) => {
console.log('Action: Cancel', id);
},
updateProfile: async (data: any) => {
console.log('Action: Update', data);
},
exportTransactions: () => {
console.log('Action: Export');
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Stub actions will cause failures in consuming components.

cancelBooking only logs and returns undefined, but TenantDashboard.handleConfirmCancel (line 88-89) checks if (success) expecting a boolean. This will always show "Failed to cancel booking".

🔧 Return explicit values for stub functions
-    cancelBooking: async (id: any) => {
-      console.log('Action: Cancel', id);
-    },
-    updateProfile: async (data: any) => {
-      console.log('Action: Update', data);
-    },
+    cancelBooking: async (id: any) => {
+      console.log('Action: Cancel', id);
+      return true; // Stub: always succeeds
+    },
+    updateProfile: async (data: any) => {
+      console.log('Action: Update', data);
+      return true; // Stub: always succeeds
+    },
📝 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.

Suggested change
cancelBooking: async (id: any) => {
console.log('Action: Cancel', id);
},
updateProfile: async (data: any) => {
console.log('Action: Update', data);
},
exportTransactions: () => {
console.log('Action: Export');
},
cancelBooking: async (id: any) => {
console.log('Action: Cancel', id);
return true; // Stub: always succeeds
},
updateProfile: async (data: any) => {
console.log('Action: Update', data);
return true; // Stub: always succeeds
},
exportTransactions: () => {
console.log('Action: Export');
},
🤖 Prompt for AI Agents
In `@apps/web/src/hooks/useDashboard.ts` around lines 169 - 177, The stub action
methods cancelBooking, updateProfile and exportTransactions currently only log
and return undefined which breaks callers (e.g.,
TenantDashboard.handleConfirmCancel expects a boolean success); update these
functions to return explicit, relevant values (e.g., cancelBooking should return
a boolean or Promise<boolean> indicating success/failure, updateProfile should
return the updated profile object or boolean/Promise<boolean>, and
exportTransactions should return a success indicator or Promise) and ensure they
resolve/reject consistently so callers can rely on their return values instead
of undefined.

Comment on lines +10 to +18
const getSDK = () => {
if (typeof window === 'undefined') return null;

const anyRoot = RootSDK as any;
// Intentamos todas las combinaciones posibles de exportación
return anyRoot.StellarSocialSDK || anyRoot.default?.StellarSocialSDK || anyRoot.default || null;
};

export const StellarSocialSDK = getSDK();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

SDK initialization executes at module load time, not runtime.

getSDK() is called at line 18 during module evaluation. While it checks typeof window === 'undefined', this check may pass during build/SSR but the exported StellarSocialSDK will be null and remain null even after hydration. Consider lazy initialization or a getter pattern.

🔧 Proposed lazy initialization
-export const StellarSocialSDK = getSDK();
+let _cachedSDK: any = undefined;
+export const getStellarSocialSDK = () => {
+  if (_cachedSDK === undefined) {
+    _cachedSDK = getSDK();
+  }
+  return _cachedSDK;
+};
+// For backward compatibility, but prefer getStellarSocialSDK()
+export const StellarSocialSDK = typeof window !== 'undefined' ? getSDK() : null;
📝 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.

Suggested change
const getSDK = () => {
if (typeof window === 'undefined') return null;
const anyRoot = RootSDK as any;
// Intentamos todas las combinaciones posibles de exportación
return anyRoot.StellarSocialSDK || anyRoot.default?.StellarSocialSDK || anyRoot.default || null;
};
export const StellarSocialSDK = getSDK();
const getSDK = () => {
if (typeof window === 'undefined') return null;
const anyRoot = RootSDK as any;
// Intentamos todas las combinaciones posibles de exportación
return anyRoot.StellarSocialSDK || anyRoot.default?.StellarSocialSDK || anyRoot.default || null;
};
let _cachedSDK: any = undefined;
export const getStellarSocialSDK = () => {
if (_cachedSDK === undefined) {
_cachedSDK = getSDK();
}
return _cachedSDK;
};
// For backward compatibility, but prefer getStellarSocialSDK()
export const StellarSocialSDK = typeof window !== 'undefined' ? getSDK() : null;
🤖 Prompt for AI Agents
In `@apps/web/src/lib/stellar-social-sdk.ts` around lines 10 - 18, The module
currently initializes the SDK at load time by calling getSDK(), so
StellarSocialSDK becomes null during SSR/build and never updates after
hydration; change to lazy initialization by replacing the exported constant with
a function or getter that resolves RootSDK at runtime (e.g., export a
getStellarSocialSDK or a lazy getter) and have it call getSDK() (or inline its
logic) when first invoked, ensuring you reference getSDK, StellarSocialSDK, and
RootSDK in the implementation so the runtime window check is executed on-demand
rather than at module-evaluation time.

Comment on lines +21 to +27
export type AuthMethod = 'google' | 'apple' | 'facebook' | 'wallet';
export type UserRole = 'guest' | 'host' | 'tenant' | 'dual';

export interface SocialAuthConfig {
clientId: string;
method: AuthMethod;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check if the file exists and read its contents
cat -n apps/web/src/lib/stellar-social-sdk.ts 2>/dev/null | head -50

Repository: Stellar-Rent/stellar-rent

Length of output: 1241


🏁 Script executed:

#!/bin/bash
# Search for other files that might contain the SDK type definitions
fd -t f "stellar-social" --max-one-result 2>/dev/null

Repository: Stellar-Rent/stellar-rent

Length of output: 51


🏁 Script executed:

#!/bin/bash
# Look for type definitions or SDK references in the codebase
rg -t ts "AuthMethod" apps/web/src --max-count=20 -A 3 -B 1

Repository: Stellar-Rent/stellar-rent

Length of output: 2136


🏁 Script executed:

#!/bin/bash
# Check the index file that's being imported
cat -n index.ts 2>/dev/null | head -100

Repository: Stellar-Rent/stellar-rent

Length of output: 216


🏁 Script executed:

#!/bin/bash
# Search for SocialAuthConfig usage
rg "SocialAuthConfig" apps/web/src -A 3 -B 1

Repository: Stellar-Rent/stellar-rent

Length of output: 344


🏁 Script executed:

#!/bin/bash
# Check if there's a real SDK package and its type definitions
rg "StellarSocialSDK" apps/web/src -A 5 -B 1 | head -50

Repository: Stellar-Rent/stellar-rent

Length of output: 2693


🏁 Script executed:

#!/bin/bash
# Look for wallet/freighter auth method implementations
rg "freighter|wallet" apps/web/src -t ts --max-count=15

Repository: Stellar-Rent/stellar-rent

Length of output: 12151


🏁 Script executed:

#!/bin/bash
# Check actual usage of SocialAuthConfig - is it used anywhere?
rg "SocialAuthConfig" apps/web/src

Repository: Stellar-Rent/stellar-rent

Length of output: 143


🏁 Script executed:

#!/bin/bash
# Check if AuthMethodData is what should be used instead
cat -n apps/web/src/types/auth.ts | head -60

Repository: Stellar-Rent/stellar-rent

Length of output: 1917


AuthMethod type definition doesn't match actual usage in the application.

The AuthMethod type defines 'google' | 'apple' | 'facebook' | 'wallet', but the actual application uses 'google' | 'freighter' (defined in types/auth.ts). The methods 'apple', 'facebook', and 'wallet' are never used, while 'freighter' is used throughout but missing from this type definition. Additionally, SocialAuthConfig is unused—it's defined but never referenced in the codebase, making it dead code.

🤖 Prompt for AI Agents
In `@apps/web/src/lib/stellar-social-sdk.ts` around lines 21 - 27, Update the
AuthMethod union to match actual usage by replacing/merging its values with the
canonical set used across the app (add 'freighter' and remove unused
'apple'|'facebook'|'wallet') so the exported AuthMethod type aligns with
types/auth.ts; also remove the unused SocialAuthConfig interface (dead code)
from apps/web/src/lib/stellar-social-sdk.ts to avoid stale exports and keep
typings consistent.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/components/shared/layout/providers.tsx (1)

30-36: ⚠️ Potential issue | 🔴 Critical

Missing Spinner import will cause a runtime error.

The Spinner component is used on line 33 but is not imported anywhere in this file. This will result in a ReferenceError when the component renders in its loading state.

🐛 Proposed fix to add the missing import

Add the import at the top of the file:

 'use client';

 import { ThemeProvider, useTheme } from 'next-themes';
 import React from 'react';
+import { Spinner } from '~/components/ui/loading-skeleton';
 import { AuthProvider } from '~/hooks/auth/use-auth';
 import { StellarProvider } from '~/hooks/stellar/stellar-context';
 import { TrustlessWorkProvider } from '~/providers/TrustlessWorkProvider';
🧹 Nitpick comments (3)
apps/web/src/components/shared/layout/providers.tsx (1)

12-20: Consider preserving existing classes on the portal element.

Setting portal.className = resolvedTheme replaces all existing classes on the theme-portal-root element. If the portal element has other classes for styling or layout, they will be lost when the theme changes.

♻️ Proposed fix to toggle theme classes instead of replacing
 function ThemePortalSync() {
   const { resolvedTheme } = useTheme();
   React.useEffect(() => {
     const portal =
       typeof window !== 'undefined' ? document.getElementById('theme-portal-root') : null;
-    if (portal && resolvedTheme) portal.className = resolvedTheme;
+    if (portal && resolvedTheme) {
+      portal.classList.remove('light', 'dark');
+      portal.classList.add(resolvedTheme);
+    }
   }, [resolvedTheme]);
   return null;
 }
apps/web/src/app/search/page.tsx (2)

19-19: Move PAGE_SIZE constant outside the component.

PAGE_SIZE is a static value that doesn't depend on props or state. Declaring it inside the component causes it to be recreated on every render and makes it a candidate for the useMemo dependency array at line 76.

♻️ Suggested refactor
+const PAGE_SIZE = 3;
+
 export default function SearchPage() {
   const [page, setPage] = useState(1);
-  const PAGE_SIZE = 3;
   const [sortOrder, setSortOrder] = useState('price_asc');

30-34: Consider hoisting mapCenter and mapMarkers outside the component.

The mapMarkers array is recreated with a new reference on every render. If child components use referential equality checks (e.g., React.memo, dependency arrays), this could trigger unnecessary re-renders.

♻️ Suggested refactor
+const DEFAULT_MAP_CENTER: LatLngTuple = [-34.61, -58.39];
+const DEFAULT_MAP_MARKERS: { position: LatLngTuple; title: string }[] = [
+  { position: [-34.61, -58.39], title: 'Modern Apartment with Kitchen' },
+  { position: [-34.6, -58.37], title: 'Cozy Studio Apartment' },
+];
+
 export default function SearchPage() {
   // ...
-  const mapCenter: LatLngTuple = [-34.61, -58.39];
-  const mapMarkers: { position: LatLngTuple; title: string }[] = [
-    { position: [-34.61, -58.39], title: 'Modern Apartment with Kitchen' },
-    { position: [-34.6, -58.37], title: 'Cozy Studio Apartment' },
-  ];

Then reference DEFAULT_MAP_CENTER and DEFAULT_MAP_MARKERS in the JSX.

@respp respp merged commit 8a1cd90 into Stellar-Rent:main Jan 30, 2026
1 check passed
@respp
Copy link
Contributor

respp commented Jan 30, 2026

closes #193

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants