diff --git a/api/getPropertiesData.js b/api/getPropertiesData.js new file mode 100644 index 0000000..c2a26f1 --- /dev/null +++ b/api/getPropertiesData.js @@ -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; + } +}; diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..c979625 --- /dev/null +++ b/api/index.js @@ -0,0 +1 @@ +export * from './getPropertiesData'; diff --git a/src/components/PropertyListing/PropertyListing.jsx b/src/components/PropertyListing/PropertyListing.jsx index ed43fb5..ad2c694 100644 --- a/src/components/PropertyListing/PropertyListing.jsx +++ b/src/components/PropertyListing/PropertyListing.jsx @@ -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 ( +
+ {error} +
+ ); + } + + if (!isLoading && properties.length === 0) { + return
No properties found.
; + } + return ( - + <> + {isLoading ? ( +
+ Loading... +
+ ) : ( +
+

+ Properties +

+ +
+ )} + ); }; diff --git a/src/components/PropertyListing/tests/PropertyListing.spec.jsx b/src/components/PropertyListing/tests/PropertyListing.spec.jsx index 807d63b..08869a8 100644 --- a/src/components/PropertyListing/tests/PropertyListing.spec.jsx +++ b/src/components/PropertyListing/tests/PropertyListing.spec.jsx @@ -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(); const propertiesList = screen.getByRole('list'); const propertyCards = await within(propertiesList).findAllByRole('listitem'); - expect(propertyCards).toHaveLength(5); + expect(propertyCards).toHaveLength(mockProperties.length); }); });