Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
456b2e2
fix: lint errors
Lynndabel May 30, 2025
c51785e
chore: remove temporary code file temp_code.txt
Lynndabel May 31, 2025
ba80157
refactor: move caniuse-lite to devDependencies
Lynndabel May 31, 2025
d679ffd
refactor: optimize HowItWorks component for performance
Lynndabel May 31, 2025
de15a53
refactor: improve autocomplete UX and accessibility in SearchBar
Lynndabel May 31, 2025
7438f75
fix: update property images to use unique image files
Lynndabel May 31, 2025
f1c847a
fix: update property images to use existing house1-5 images
Lynndabel May 31, 2025
5fd7e7a
refactor: remove unnecessary Suspense boundary in FeaturedProperties …
Lynndabel May 31, 2025
5830524
fix: replace Next.js Link with anchor tags for external social media …
Lynndabel May 31, 2025
fc6efe6
fix: add group class to button in HeroSection to enable arrow animation
Lynndabel May 31, 2025
63a12bf
fix: remove padding and centering from root layout main element to fi…
Lynndabel May 31, 2025
5a24a0f
fix: adjust arrow positioning in HowItWorks component
Lynndabel May 31, 2025
1f39b48
chore: remove unused dependencies (date-fns, @next/swc-win32-x64-msvc…
Lynndabel May 31, 2025
e028137
chore: remove bash.exe.stackdump file
Lynndabel May 31, 2025
97c018f
Merge branch 'main' of https://github.com/Lynndabel/stellar-rent into…
Lynndabel May 31, 2025
e994269
feat: add property images for rental listings
Lynndabel May 31, 2025
308e01f
fix: improve SearchBar suggestion accessibility with ARIA attributes
Lynndabel May 31, 2025
bbe25bd
fix: add proper label association to guest selector for accessibility
Lynndabel May 31, 2025
485361a
refactor: replace hardcoded property features with dynamic data
Lynndabel May 31, 2025
84e47e1
feat: add dynamic booking functionality with state management
Lynndabel May 31, 2025
87d9866
fix: use meaningful keys for guest selector options
Lynndabel May 31, 2025
c37a234
feat: improve error handling for missing properties with user-friendl…
Lynndabel May 31, 2025
25c949d
fix: improve accessibility of location dropdown with proper ARIA attr…
Lynndabel May 31, 2025
9080ca4
fix: add proper Property type annotation to fix TypeScript warning
Lynndabel May 31, 2025
d38811a
refactor: improve date calculation robustness with dedicated function
Lynndabel May 31, 2025
478cb89
feat: add image error handling with fallback UI
Lynndabel May 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/web/next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
// Disable SWC compilation
swcMinify: false,
reactStrictMode: true,
transpilePackages: ['@stellar-rent/ui'],
webpack: (config) => {
Expand Down
3 changes: 3 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
"@radix-ui/react-dropdown-menu": "^2.1.12",
"@radix-ui/react-form": "^0.1.6",
"@radix-ui/react-label": "^2.1.4",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-slot": "^1.2.0",
"@simplewebauthn/browser": "^13.1.0",
"@stellar/stellar-sdk": "^13.3.0",
"base64url": "^3.0.1",
"bigint-conversion": "^2.4.3",

"cbor-x": "^1.6.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand All @@ -31,6 +33,7 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.0",
"react-hot-toast": "^2.5.2",
"react-intersection-observer": "^9.16.0",
"sodium-universal": "^5.0.1",
"stellar-sdk": "^13.3.0",
"tailwind-merge": "^3.2.0",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/house.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/house1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/house2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/house3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/house4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/images/house5.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/web/public/images/property-1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function RootLayout({
<div id="theme-portal-root" />
<Providers>
<Navbar />
<main className="flex-1 flex flex-col items-center justify-between p-2">{children}</main>
<main className="flex-1 flex flex-col">{children}</main>
<Toaster position="top-right" />
</Providers>
</body>
Expand Down
40 changes: 33 additions & 7 deletions apps/web/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,39 @@
import Image from 'next/image';
import { FeaturedProperties } from '@/components/features/properties/FeaturedProperties';
import { SearchBar } from '@/components/features/search/SearchBar';
import { HowItWorks } from '@/components/shared/HowItWorks';
import { Testimonials } from '@/components/shared/Testimonials';
import { Footer } from '@/components/shared/layout/Footer';
import { HeroSection } from '@/components/shared/layout/HeroSection';
import { Suspense } from 'react';

export default function Home() {
const mensaje = 'Hola Mundo';
const fecha = new Date().toLocaleDateString();

return (
<main className="flex flex-1 flex-col items-center justify-between p-8">
<h1>{mensaje}</h1>
<p>Fecha: {fecha}</p>
<main className="flex flex-1 flex-col w-full">
{/* Hero Section */}
<section id="hero" className="relative">
<HeroSection />
<div className="relative z-10">
<SearchBar />
</div>
</section>

{/* Featured Properties Section */}
<Suspense fallback={<div className="py-16 text-center">Loading properties...</div>}>
<FeaturedProperties />
</Suspense>

{/* How It Works Section */}
<section id="how-it-works">
<HowItWorks />
</section>

{/* Testimonials Section */}
<section id="testimonials">
<Testimonials />
</section>

{/* Footer */}
<Footer />
</main>
);
}
32 changes: 32 additions & 0 deletions apps/web/src/app/property/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { Metadata } from 'next';
import PropertyDetail from '@/components/features/properties/PropertyDetail';

// This would typically come from an API
const getPropertyById = async (id: string) => {
// In a real app, this would be an API call
// For now, we're mocking it and leveraging the component's built-in data
return { id };
};
Comment on lines +5 to +9
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

Remove redundant mock function that creates confusion.

The getPropertyById function here only returns { id }, but the PropertyDetail component calls its own getPropertyById function expecting full property data. This creates redundant data fetching and architectural confusion.

Apply this diff to simplify the implementation:

-// This would typically come from an API
-const getPropertyById = async (id: string) => {
-  // In a real app, this would be an API call
-  // For now, we're mocking it and leveraging the component's built-in data
-  return { id };
-};

And update the component:

export default async function PropertyPage({ params }: Props) {
  const { id } = params;
  
-  // In a real app, this would fetch property data from an API
-  // and pass it to the PropertyDetail component
-  await getPropertyById(id);
-  
  return <PropertyDetail id={id} />;
}
📝 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 getPropertyById = async (id: string) => {
// In a real app, this would be an API call
// For now, we're mocking it and leveraging the component's built-in data
return { id };
};
export default async function PropertyPage({ params }: Props) {
const { id } = params;
return <PropertyDetail id={id} />;
}
🤖 Prompt for AI Agents
In apps/web/src/app/property/[id]/page.tsx around lines 5 to 9, remove the
redundant getPropertyById mock function that only returns { id } and causes
confusion with the PropertyDetail component's own data fetching. Instead,
simplify the implementation by deleting this function and updating the component
to directly use the full property data it requires without relying on this
incomplete mock.


type Props = {
params: { id: string };
};

export async function generateMetadata({ params }: Props): Promise<Metadata> {
// Fetch property details to use in metadata
// In a real app, this would come from an API
return {
title: `Property ${params.id} | StellarRent`,
description: `View details and book property ${params.id} with cryptocurrency on StellarRent.`,
};
}

export default async function PropertyPage({ params }: Props) {
const { id } = params;

// In a real app, this would fetch property data from an API
// and pass it to the PropertyDetail component
await getPropertyById(id);

return <PropertyDetail id={id} />;
}
172 changes: 172 additions & 0 deletions apps/web/src/components/features/properties/FeaturedProperties.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
'use client';

import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import { Heart, MapPin, Star } from 'lucide-react';
import Image from 'next/image';
import Link from 'next/link';
import { Suspense, useState } from 'react';
import { useInView } from 'react-intersection-observer';

// Types
type Property = {
id: string;
title: string;
location: string;
price: number;
image: string;
rating: number;
distance: string;
};

// Mock data for properties
const MOCK_PROPERTIES: Property[] = [
{
id: '1',
title: 'Modern Apartment with Kitchen',
location: 'Luján, Buenos Aires',
price: 2500,
image: '/images/house1.jpg',
rating: 4.1,
distance: '30km',
},
{
id: '2',
title: 'Luxury Villa with Pool',
location: 'Luján, Buenos Aires',
price: 6000,
image: '/images/house2.jpg',
rating: 4.8,
distance: '6km',
},
{
id: '3',
title: 'Cozy Bedroom Suite',
location: 'Luján, Buenos Aires',
price: 4500,
image: '/images/house3.jpg',
rating: 3.9,
distance: '14km',
},
{
id: '4',
title: 'Elegant Studio Apartment',
location: 'Luján, Buenos Aires',
price: 5600,
image: '/images/house4.jpg',
rating: 4.5,
distance: '8km',
},
{
id: '5',
title: 'Charming Kitchen Loft',
location: 'Luján, Buenos Aires',
price: 2100,
image: '/images/house5.jpg',
rating: 4.2,
distance: '12km',
},
{
id: '6',
title: 'Modern Architectural House',
location: 'Luján, Buenos Aires',
price: 6500,
image: '/images/house.jpg',
rating: 4.7,
distance: '10km',
},
];

// Property Card Component
const PropertyCard = ({ property }: { property: Property }) => {
// Use IntersectionObserver to detect when the card comes into view
const { ref, inView } = useInView({
triggerOnce: true,
threshold: 0.1,
});

return (
<div
ref={ref}
className={`transition-opacity duration-500 ${inView ? 'opacity-100' : 'opacity-0'}`}
>
<Card className="overflow-hidden h-full">
<div className="relative h-48 w-full">
<div className="absolute top-2 left-2 z-10 bg-white/90 dark:bg-[#0B1D39]/90 px-2 py-1 rounded-md text-sm font-medium">
${property.price} <span className="text-xs">USDC</span>
</div>
<div className="absolute top-2 right-2 z-10">
<Button
variant="ghost"
size="icon"
className="rounded-full bg-white/30 hover:bg-white/50 text-white"
>
<Heart className="w-5 h-5" />
</Button>
</div>
<div className="absolute bottom-2 left-2 z-10 bg-white/90 dark:bg-[#0B1D39]/90 px-2 py-1 rounded-md text-xs font-medium flex items-center">
<MapPin className="w-3 h-3 mr-1" /> {property.distance}
</div>
<div className="absolute bottom-2 right-2 z-10 bg-white/90 dark:bg-[#0B1D39]/90 px-2 py-1 rounded-md text-xs font-medium flex items-center">
<Star className="w-3 h-3 mr-1 text-yellow-500" /> {property.rating}
</div>
{/* Fallback image with linear gradient if actual image fails to load */}
<div className="relative h-full w-full">
<Image
src={property.image}
alt={property.title}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
</div>
<div className="p-4">
<h3 className="font-semibold text-lg mb-1 line-clamp-1">{property.title}</h3>
<p className="text-muted-foreground text-sm mb-3 flex items-center">
<MapPin className="w-4 h-4 mr-1" /> {property.location}
</p>
<Button asChild className="w-full">
<Link href={`/property/${property.id}`}>View Details</Link>
</Button>
Comment on lines +130 to +132
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify property detail routes exist.

The component links to /property/${property.id} routes, but it's unclear if these routes are implemented.

Please verify that the property detail routes are implemented:


🏁 Script executed:

#!/bin/bash
# Check for property detail page implementation
echo "Checking for property detail route implementation..."

# Look for dynamic property routes
fd -t f "\\[.*\\]" apps/web/src/app/ | grep -i property || echo "No dynamic property routes found"

# Look for property-related page files
fd -t f "page.tsx" apps/web/src/app/ | xargs grep -l "property" 2>/dev/null || echo "No property-related pages found"

# Check for property detail components
rg -l "PropertyDetail|PropertyPage" apps/web/src/components/ || echo "No property detail components found"

Length of output: 524


Property detail route is missing

I ran a search and found no implementation for the /property/[id] route or corresponding detail components. As-is, the “View Details” link will 404. Please add:

  • A dynamic page at apps/web/src/app/property/[id]/page.tsx
  • A PropertyDetail (or PropertyPage) component that fetches and displays the property by ID

For example:

// apps/web/src/app/property/[id]/page.tsx
import { GetPropertyById } from 'lib/api'
import PropertyDetail from 'src/components/features/properties/PropertyDetail'

export default async function PropertyPage({ params: { id } }) {
  const property = await GetPropertyById(id)
  return <PropertyDetail property={property} />
}
🤖 Prompt for AI Agents
In apps/web/src/components/features/properties/FeaturedProperties.tsx around
lines 130 to 132, the link to `/property/${property.id}` points to a route that
does not exist, causing 404 errors. To fix this, create a dynamic route page at
apps/web/src/app/property/[id]/page.tsx that fetches the property by ID and
renders a PropertyDetail or PropertyPage component displaying the property
details. Implement the page as an async function that calls a data fetching
method like GetPropertyById and returns the detail component with the fetched
data.

</div>
</Card>
</div>
);
};

// Fallback loading component
const PropertyCardSkeleton = () => (
<Card className="overflow-hidden h-full">
<div className="h-48 w-full bg-muted animate-pulse" />
<div className="p-4">
<div className="h-6 bg-muted animate-pulse rounded mb-2" />
<div className="h-4 bg-muted animate-pulse rounded mb-4 w-3/4" />
<div className="h-10 bg-muted animate-pulse rounded" />
</div>
</Card>
);

// Main component
export const FeaturedProperties = () => {
return (
<section className="py-16 bg-gradient-to-b from-white to-blue-50 dark:from-[#0B1D39] dark:to-[#071429]">
<div className="container mx-auto px-4">
<div className="flex flex-col items-center mb-12 text-center">
<h2 className="text-3xl md:text-4xl font-bold mb-4">Featured Properties</h2>
<p className="text-muted-foreground max-w-2xl">
Discover our handpicked selection of premium properties available for rent with
cryptocurrency.
</p>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{MOCK_PROPERTIES.map((property) => (
<PropertyCard key={property.id} property={property} />
))}
</div>
</div>
</section>
);
};
Loading
Loading