The Car Listings Application is a full-stack web application designed to allow users to browse and interact with car listings. Users can view detailed specifications of cars and apply for trade-ins.
This app uses React, TypeScript, and Tailwind CSS for the frontend, and a Node.js API with PostgreSQL for backend functionality.
You can see the screenshots from the desktop and mobile at the bottom.
You can have a look at the live preview link:
Check out the complete UI design in Figma:
Figma UI Design
- 🚗 Car Listings: View detailed pages for each car listing, including make, model, images, and specifications.
- 🔄 Trade-In Application: Users can apply for a trade-in directly from the car's details page.
- 📝 Form Submission: The trade-in form accepts essential vehicle information (make, model, year, mileage) and allows image uploads.
- ✅ Form Validation: Backend and frontend form validation powered by Zod.
- 🔐 Authentication/Login: Secure login with JWT for user authentication.
- 💡 User Experience Enhancements: Clean, user-friendly design elements for improved usability.
- 📦 Mocked Data: The app uses mocked data for demonstration, hosted in memory.
- 🔢 Sorting & Cursor-based Infinite Scroll: Sort car listings by price, year, and mileage while using infinite scrolling.
- 🔍 Search Functionality: Search for cars by make and model.
- 🔄 Infinite Scrolling: The car listing page supports infinite scrolling, loading additional cars as the user scrolls down.
- React 📦
- TypeScript 🖋️
- Figma for Complete Design 🎨
- Tailwind CSS for a fully responsive design across different devices 📱💻
- Framer Motion & Swiper for animations 🎞️
- React Hook Form for form handling 📝
- Zod for form validation 🔒
- Axios for HTTP requests 🌐
- Node.js 🟢
- NestJS 🐦
- Prisma ORM 🔗
- PostgreSQL 🗄️
backend/
├── .env
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── nest-cli.json
├── package-lock.json
├── package.json
├── prisma/
├── src/
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── auth/
│ │ ├── auth.controller.spec.ts
│ │ ├── auth.controller.ts
│ │ ├── auth.middleware.ts
│ │ ├── auth.module.ts
│ │ ├── auth.service.spec.ts
│ │ └── auth.service.ts
│ ├── cars/
│ │ ├── cars.controller.ts
│ │ ├── cars.module.ts
│ │ ├── cars.service.ts
│ │ └── cars.types.ts
│ ├── trade-in/
│ │ ├── trade-in.controller.ts
│ │ ├── trade-in.module.ts
│ │ └── trade-in.service.ts
│ ├── users/
│ │ ├── users.module.ts
│ │ ├── users.service.spec.ts
│ │ └── users.service.ts
│ ├── utils/
│ │ └── dollarFormatter.ts
│ └── main.ts
├── test/
└── tsconfig.build.json
Frontend Folder Structure
frontend/
├── .gitignore
├── index.css
├── main.tsx
├── package.json
├── vite-env.d.ts
├── src/
│ ├── components/
│ │ ├── Footer.tsx
│ │ ├── Gallery.tsx
│ │ ├── Navbar.tsx
│ │ ├── Toast.tsx
│ │ ├── Topbar.tsx
│ │ ├── TradeInForm.tsx
│ │ └── ui/
│ │ ├── CarBrandIcon.tsx
│ │ ├── CustomButton.tsx
│ │ ├── EngineTypeIcon.tsx
│ │ ├── ScrollToTop.tsx
│ │ └── SortDropdown.tsx
│ ├── config/
│ │ └── endpoints.ts
│ ├── containers/
│ │ └── CarList.tsx
│ ├── controllers/
│ │ ├── carController.tsx
│ │ ├── carDetailsController.tsx
│ │ ├── loginFormController.tsx
│ │ └── tradeInFormController.tsx
│ ├── hooks/
│ │ └── useInfiniteScroll.tsx
│ ├── lib/
│ │ └── utils.ts
│ ├── models/
│ │ └── car.ts
│ ├── services/
│ │ └── providers/
│ │ ├── LocationProvider.tsx
│ │ └── RouteChangeProvider.tsx
│ ├── store/
│ │ ├── CarStore.ts
│ │ ├── FormStore.ts
│ │ ├── LoginStore.ts
│ │ ├── SearchQueryStore.ts
│ │ └── SortQueryStore.ts
│ ├── utils/
│ └── views/
└── tsconfig.json
🗄️ Database Structure
The database is powered by PostgreSQL and managed using Prisma. The key models include:
1. 🚗 Car
• Stores details about each car listing, including make, model, year, price, engine type, and more.
• Relation with TradeIn.
2. 👤 User
• Represents users, storing their credentials (username, email, password).
• Relation with TradeIn.
3. 🔄 TradeIn
• Stores information about user trade-in applications, including car details, status (pending, accepted, rejected), and images.
• Relation with User and Car.
model Car {
id Int @id @default(autoincrement())
make String
model String
year Int
price Float
engineType String
engineDisplacement String
power Int
transmission String
mileage Int
imageUrl String
interiorFeatures String
safetyFeatures String
serviceHistory String
financingOptions String
description String
TradeIn TradeIn[]
}
model User {
id Int @id @default(autoincrement())
username String @unique
email String @unique
password String
createdAt DateTime @default(now())
tradeIns TradeIn[]
}
model TradeIn {
id Int @id @default(autoincrement())
fullName String
phone String
email String
make String
model String
status String @default("PENDING")
year Int
mileage Int
imageUrls String[]
transmission String
fuelType String
interiorFeatures String?
safetyFeatures String?
serviceHistory String?
userId Int // Foreign key to User
user User @relation(fields: [userId], references: [id])
carId Int // Foreign key to Car
car Car @relation(fields: [carId], references: [id])
createdAt DateTime @default(now())
}