I built a responsive server-rendered real estate listing page, APIs, and tour scheduling functions for a client in February–March 2020. Here are the client's original requirements:
This project is best suited to be built by someone who considers, at least to a degree, themselves a full stack developer. You will be in charge of the design, UI, front-end, and back-end.
We are building a real estate solution enabling “For Sale By Owners” to represent themselves without a Real Estate Agent.
I am reaching out in hopes you can assist in creating the public listing/property page of our solution. The public listing page would need to be built using Next.js, Redux, React-Thunks, Express. We are using Firebase & Firestore for the backend.
Please be mindful we are completely self taught and have no formal experience in contracting out work, working with a team, etc. We will be very receptive to your suggestions to improve flow, efficiency, and design.
HI FI MOCK UP LINK:
1. Project Overview
The scope of this project includes but not limited to the following:
- Server Side Authentication through firebase, firestore
- Creating UI & State for all parts and features of the page
- Creating the UI & State for the supporting pages (provided in the mock up)
- Creating efficient database queries/writes through redux actions
The project requires the following:
- Next.js for server side rendering
- Redux for State Management
- Material-UI as the CSS framework
- Google Firebase/Firestore / Google Cloud
Other dependencies preferable but not required:
7. Feature Breakdown
- Photo Gallery
- Must function like to Homes.com photo gallery
- Has ability to upload video
- One picture/thumbnail links to google maps (similar to homes.com)
- Example Link: https://www.homes.com/property/8462-primrose-st-norfolk-va-23503/id-400028619731/
- Wire up to firebase auth to accept google and facebook login
- Limits access to specified parts of listings page when unauthenticated
- Register form will ask the user to upload proof of funds or pre-approval letter. Form should accept jpeg, png, and pdf formats.
- Each listing has a user determined general availability for time and days they are able to show the property and the schedule should reflect this.
- Design it to accomodate 30 minute or hourly increments depending homeowner preference in database
- Read and display real-time availability from database
- Real time availability includes homeowners general availability and appointments already booked. 1 appointment per slot
- Availability has 15 minute gap between appointments
- This is most important feature on the listing page
- “Start a conversation / Make an offer” buttons don't require any functionality. Just add them to the UI
- Login is required to book an appointment
- Questions & Answers
- Questions and Answers are displayed based on the homeowner setting questions public or private.
- Login is not required to book an appointment. If they are not authenticated, they must submit name, email, and question. If they are authenticated, form should only ask for the question.
- Login not required to download
- Listing has a document collection that includes id, name, description, download link
- Design should be similar to mock up but there is wiggle room to make this how you like
- Home Details
- Initial state should show 14 items from the database
- When they click view more, it should pull all home details from the database. This amount could differ between homeowners.
- Need UI functionality for the expandable tabs (calculator, mortgage rate, nearby school). We will add the calculator, mortgage rate, and school apis ourselves.
- Add it to the UI but doesn't need to be fully functional
Keep the design as close to the mock-up as needed. Functionality takes priority over aesthetics and form. With that being the case, please make the page as clean and minimal as possible.
Colors: Use the mock up as a guide or your own discretion but we plan to go back in and add our themed colors for headings/ subtitles/buttons/etc.
I ended up making the following recommendations, all of which the client agreed with:
Don't use Express – Using both Next.js and Express at the same time seemed a bit redundant. I'd found several tutorials online for connecting the two together, so it's easy enough to do, but the general reason I saw for using both together is that Express can keep URLs cleaner by using route parameters instead of just query strings, but Next.js had had dynamic routing features as long as I had been using it. And Next.js allows for API routes, which can be dynamic as well, so from my perspective, Express just added unnecessary complexity.
Don't use Redux – I'm a big fan of Redux and have used it effectively in the past in a single-page React app, but it seemed unnecessary for an app connected to a database, especially when using Next.js for server-rendering pages. As far as I could tell, where Redux becomes useful in a database-connected app is when data is initially fetched by lower-level components but later needed by other components that are not children of the original component. Redux then becomes a more intuitive alternative to lifting state up within the app.
If using Next.js specifically for server-side rendering, though (which would be helpful in this application for SEO for individual home listings), you'd already be fetching data at the page level, using
getInitialProps, so the page component would already be able to pass any necessary state data as props to any child component that required them—no need to lift the state any higher than that. Adding a Redux store would just be redundant at that point; you can create more efficient database queries/writes in your own functions than by using Redux actions.
Use Formik instead of Redux Form – Formik, being more scalable and minimal, would serve this application much better than Redux Form. It's rare that form state, pre-submission, would ever need to be shared with components outside the form itself.
Use React Bootstrap instead of Material-UI – Mostly a personal design preference. I found Material-UI's documentation to be pretty bad, and it was much more difficult to style than React Bootstrap. Material-UI out of the gate looked aggressively like a giant Android phone app, which I thought was fine for dashboard applications, but I thought it would feel like less of a website to normal users.
The design of the listing page was inspired by the general layout of a prototype the client made on Proto.io, but I did recreate it from scratch. Here are a few of the design points I'm particularly proud of:
The photo grid was largely custom-built, its only external dependencies being React Bootstrap for the grid framework and expand/collapse function and React Images for the lightbox gallery. That kind of arrangement of the photos, though, I couldn't find anywhere else, especially the functionality of allowing images to take up multiple rows and multiple columns at the same time, and handling portrait photos attractively. So I wrote that arrangement algorithm myself.
The client wished for the scheduling widget on the main listing page to remain in view at all times, which was easy to accomplish on wider screens with sticky positioning in its own column, but in the single-column layout on small screens, this large widget was covering half the screen once you scrolled past it. To fix this, I designed a miniature version of the widget that would hide behind the larger widget until the users scrolls past, after which the mini-widget would stick to the top of the screen, leaving plenty of room to see the rest of the content.
The main scheduling page queries both the home's and the user's current tour schedules in a Cloud Firestore database and disables the buttons for any conflicting days and times so they cannot be scheduled. The page and accompanying APIs also ensure that time zones are handled correctly using Luxon, and an informational message clarifying the time zone appears on the page when it detects that the user is in a different time zone from the home itself.
Hope you enjoy this demo, and if you'd like me to build something similar for you, I'd love to get in touch!