Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions api/getPropertiesData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const PROPERTIES_URL = 'http://localhost:3000/api/properties';

export const getPropertiesData = async () => {
try {
const response = await fetch(PROPERTIES_URL);
if (!response.ok) {
throw new Error(`Response status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error(`Error fetching properties:`, error);
throw error;
}
};
1 change: 1 addition & 0 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './getPropertiesData';
88 changes: 63 additions & 25 deletions src/components/PropertyListing/PropertyListing.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,71 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import PropertyCard from '../PropertyCard';
import './PropertyListing.scss';

const DUMMY_PROPERTY = {
id: 73864112,
bedrooms: 3,
summary: 'Property 1 Situated moments from the River Thames in Old Chelsea...',
displayAddress: '1 CHEYNE WALK, CHELSEA, SW3',
propertyType: 'Flat',
price: 1950000,
branchName: 'M2 Property, London',
propertyUrl: '/property-for-sale/property-73864112.html',
contactUrl: '/property-for-sale/contactBranch.html?propertyId=73864112',
propertyTitle: '3 bedroom flat for sale',
mainImage:
'https://media.rightmove.co.uk/dir/crop/10:9-16:9/38k/37655/53588679/37655_CAM170036_IMG_01_0000_max_476x317.jpg',
};
import { getPropertiesData } from '../../../api/getPropertiesData';

const PropertyListing = () => {
const [properties, setProperties] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const fetchData = async () => {
try {
setProperties(await getPropertiesData());
} catch (err) {
setError('Failed to load properties');
} finally {
setIsLoading(false);
}
};
fetchData();
}, []);

if (error) {
return (
<div className="error-message" role="alert">
{error}
</div>
);
}

if (!isLoading && properties.length === 0) {
return <div role="status">No properties found.</div>;
}

return (
<ul className="PropertyListing">
{Array(5)
.fill(DUMMY_PROPERTY)
.map((property, index) => (
<li key={index}>
<PropertyCard {...property} />
</li>
))}
</ul>
<>
{isLoading ? (
<div data-testid="loading-spinner" role="status">
Loading...
</div>
) : (
<div
style={{
display: 'flex',
flexDirection: 'column',
}}
>
<h2 id="property-list-heading" style={{ textAlign: 'center', marginBottom: '1rem' }}>
Properties
</h2>
<ul
style={{
listStyle: 'none',
padding: 0,
margin: 0,
}}
className="property-listing"
>
{properties.map((property, index) => (
<li key={index}>
<PropertyCard {...property} />
</li>
))}
</ul>
</div>
)}
</>
);
};

Expand Down
45 changes: 43 additions & 2 deletions src/components/PropertyListing/tests/PropertyListing.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,52 @@ import { render, screen } from '@testing-library/react';
import { within } from '@testing-library/dom';
import PropertyListing from '../PropertyListing';

const mockProperties = [
{
id: 1,
bedrooms: 2,
summary: 'Summary for property 1.',
displayAddress: '123 Dummy Street, Testville',
propertyType: 'Detached',
price: 100000,
branchName: 'Test Branch',
propertyUrl: '/property-for-sale/property-1.html',
contactUrl: '/property-for-sale/contactBranch.html?propertyId=1',
propertyTitle: '2 bedroom detached house for sale',
mainImage: 'https://dummyimage.com/000000.jpg&text=Property+1',
},
{
id: 2,
bedrooms: 3,
summary: 'Summary for property 2.',
displayAddress: '456 Example Avenue, Mocktown',
propertyType: 'Flat',
price: 200000,
branchName: 'Mock Branch',
propertyUrl: '/property-for-sale/property-2.html',
contactUrl: '/property-for-sale/contactBranch.html?propertyId=2',
propertyTitle: '3 bedroom flat for sale',
mainImage: 'https://dummyimage.com/000000.jpg&text=Property+2',
},
];

describe('PropertyListing', () => {
it('should render five property cards', async () => {
beforeEach(() => {
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve(mockProperties),
})
);
});

afterEach(() => {
jest.resetAllMocks();
});
it('should render the property cards correctly', async () => {
render(<PropertyListing />);
const propertiesList = screen.getByRole('list');
const propertyCards = await within(propertiesList).findAllByRole('listitem');
expect(propertyCards).toHaveLength(5);
expect(propertyCards).toHaveLength(mockProperties.length);
});
});