Rent-a-phone

Rent-a-Phone πŸ“±

A full-stack phone rental web application built with React 18 + TypeScript + Vite (frontend) and Express + SQLite (backend). Rent smartphones by the day with transparent MRP-based pricing, refundable deposits, and a membership programme.

Live Demo: After hosting, update this link.


Features

Core Rental System

Membership Programme (β‚Ή10,000/year)

Payment System (Mock Razorpay-Style)

Authentication & Security

UI & Marketing


Project Structure

Rent-a-Phone/
β”œβ”€β”€ frontend/                      # React 18 + TypeScript + Vite
β”‚   β”œβ”€β”€ public/
β”‚   β”‚   └── assets/images/         # Fallback SVG
β”‚   └── src/
β”‚       β”œβ”€β”€ api/index.ts           # Axios client, types, API functions
β”‚       β”œβ”€β”€ components/
β”‚       β”‚   β”œβ”€β”€ Navbar.tsx          # Nav bar with membership link
β”‚       β”‚   β”œβ”€β”€ PhoneCard.tsx       # Phone card with OS, deposit, premium badge
β”‚       β”‚   β”œβ”€β”€ ProtectedRoute.tsx  # Auth guard
β”‚       β”‚   └── RentalModal.tsx     # Date-picker rental modal
β”‚       β”œβ”€β”€ context/
β”‚       β”‚   β”œβ”€β”€ AuthContext.tsx     # JWT auth + expiry check
β”‚       β”‚   └── CartContext.tsx     # Shopping cart state
β”‚       β”œβ”€β”€ data/
β”‚       β”‚   └── catalog.ts         # 30 phones: images, specs, pricing, tiers
β”‚       β”œβ”€β”€ pages/
β”‚       β”‚   β”œβ”€β”€ Home.tsx           # Hero + marketing + membership promo
β”‚       β”‚   β”œβ”€β”€ Phones.tsx         # Filterable phone grid
β”‚       β”‚   β”œβ”€β”€ PhoneDetail.tsx    # Full specs, deposit, rent-to-own progress
β”‚       β”‚   β”œβ”€β”€ Cart.tsx           # Cart with deposit totals
β”‚       β”‚   β”œβ”€β”€ Checkout.tsx       # Razorpay-style UPI/Card/NetBanking
β”‚       β”‚   β”œβ”€β”€ Membership.tsx     # Membership subscribe + status
β”‚       β”‚   β”œβ”€β”€ MyRentals.tsx      # User's rental history
β”‚       β”‚   β”œβ”€β”€ Login.tsx          # User login
β”‚       β”‚   β”œβ”€β”€ Register.tsx       # User registration
β”‚       β”‚   β”œβ”€β”€ Admin.tsx          # Phone catalog management
β”‚       β”‚   └── AdminLogin.tsx     # Admin authentication
β”‚       β”œβ”€β”€ utils/
β”‚       β”‚   β”œβ”€β”€ catalogStore.ts    # localStorage catalog read/write
β”‚       β”‚   └── pricing.ts        # Discount & rent-to-own calculations
β”‚       β”œβ”€β”€ App.tsx                # Routes
β”‚       └── index.css              # Full design system (~2000 lines)
β”œβ”€β”€ backend/
β”‚   └── src/
β”‚       β”œβ”€β”€ db.ts                  # SQLite setup, migrations, 30-phone seed
β”‚       β”œβ”€β”€ index.ts               # Express entry, CORS, routes
β”‚       β”œβ”€β”€ middleware/auth.ts     # JWT verification middleware
β”‚       └── routes/
β”‚           β”œβ”€β”€ phones.ts          # GET /api/phones (with OS, premium_only)
β”‚           β”œβ”€β”€ auth.ts            # POST login/register (with membership status)
β”‚           β”œβ”€β”€ rentals.ts         # POST/GET rentals (deposit, premium check)
β”‚           └── membership.ts      # GET status, POST subscribe
β”œβ”€β”€ scripts/
β”‚   └── update-phones.ts           # CLI tool to update phone catalog
β”œβ”€β”€ .gitignore
└── README.md

Getting Started

Prerequisites

1. Clone the repository

git clone https://github.com/EnsieT/rent-a-phone.git
cd rent-a-phone

2. Backend setup

cd backend
npm install

Create a .env file (or use the included .env.example):

JWT_SECRET=change-me-in-production
PORT=3001

Start the backend:

npx tsx src/index.ts
# or: npm run dev  (uses ts-node-dev)
# Server runs at http://localhost:3001

The SQLite database is auto-created in backend/data/rental.db on first run with all 30 phones seeded.

3. Frontend setup

cd frontend
npm install
npm run dev
# Runs at http://localhost:5173

4. Open in browser

Visit http://localhost:5173 β€” register an account and start browsing phones.

Admin panel: Go to /admin-login and log in with:


Pricing Model

MRP β†’ Buy Price β†’ Rent Per Day

Each phone has an MRP (retail price). The buy price depends on condition:

Condition Factor Example (MRP β‚Ή1,00,000)
Mint 85% β‚Ή85,000
Like New 80% β‚Ή80,000
Good 65% β‚Ή65,000
Fair 50% β‚Ή50,000

Rent per day = Math.round(buyPrice / 400)

Volume Discounts

Days Rented Discount
0–29 0%
30–59 3%
60–89 6%
90–119 9%
… …
300+ 30% (max)

Formula: discount = floor(days / 30) Γ— 3%, capped at 30%.

Deposit

Every rental requires a refundable deposit = buy price. Members get β‚Ή9,000 off each deposit.

Rent-to-Own

After 365 cumulative rental days on a specific phone, you become eligible for the rent-to-own programme.


Membership

Feature Detail
Price β‚Ή10,000 / year
Deposit discount β‚Ή9,000 off every rental deposit
Premium phone access 4 exclusive flagship devices
Refund policy 100% refundable
Priority support βœ“

Premium-only phones: iPhone 15 Pro Max, iPhone 15 Pro, Galaxy S24 Ultra, Galaxy Z Fold 5.


Updating Phone Catalog

Quick method β€” Edit catalog.ts

The frontend phone catalog lives in frontend/src/data/catalog.ts. Each phone entry looks like:

{
  id: 31,
  brand: 'Samsung',
  model: 'Galaxy S25',
  description: 'Latest Samsung flagship.',
  tier: 'premium',        // 'budget' | 'mid-tier' | 'premium'
  imagePath: 'https://fdn2.gsmarena.com/vv/bigpic/samsung-galaxy-s25.jpg',
  ram: '12 GB',
  storage: '256 GB',
  os: 'Android 15 (One UI 7)',
  condition: 'Mint',       // 'Mint' | 'Like New' | 'Good' | 'Fair'
  mrp: 79999,
  available: true,
  premiumOnly: false,      // true = members only
}

Buy price and rent/day are auto-calculated from MRP Γ— condition factor.

CLI Script β€” scripts/update-phones.ts

A guided script to add, edit, or remove phones from both catalog files at once:

npx tsx scripts/update-phones.ts

This will prompt you to:

  1. List all current phones
  2. Add a new phone (guided prompts)
  3. Edit an existing phone by ID
  4. Remove a phone by ID
  5. Find image URL β€” opens GSMArena search tips

Changes are written to both frontend/src/data/catalog.ts and backend/src/db.ts.

Finding phone images

All images use GSMArena product photos. To find an image URL for a new phone:

  1. Go to gsmarena.com
  2. Search for the phone model
  3. Right-click the main product image β†’ Copy image address
  4. The URL format is: https://fdn2.gsmarena.com/vv/bigpic/{phone-slug}.jpg

Phone Tiers

Tier MRP Range Examples
Budget Under β‚Ή20,000 Redmi Note 13 Pro, Galaxy M34, Poco X5 Pro
Mid-Tier β‚Ή20,000 – β‚Ή50,000 iPhone 14, Pixel 7a, Nothing Phone (2)
Premium β‚Ή50,000+ iPhone 15 Pro Max, Galaxy S24 Ultra, OnePlus 12

Tech Stack

Layer Technology
Frontend React 18, TypeScript, Vite
Styling Plain CSS (custom design system)
Routing React Router v6
HTTP Axios
Backend Express.js, TypeScript
Database SQLite via better-sqlite3
Auth JWT (jsonwebtoken + bcryptjs)
Images GSMArena product photos

API Endpoints

Method Endpoint Auth Description
GET /api/phones No List all phones (with OS, tier)
POST /api/auth/register No Register new user
POST /api/auth/login No Login, returns JWT + membership
GET /api/rentals JWT Get user’s rentals
POST /api/rentals JWT Create rental (deposit calculated)
GET /api/membership/status JWT Check membership status
POST /api/membership/subscribe JWT Subscribe to membership

Hosting on GitHub Pages (Frontend) + Render/Railway (Backend)

See the Hosting Guide section below for step-by-step deployment instructions.

Option A: GitHub Pages (Frontend Only β€” Static)

  1. Build the frontend:
    cd frontend
    npm run build
    
  2. The output goes to frontend/dist/.
  3. Push to GitHub and enable Pages in repo Settings β†’ Pages β†’ Source: gh-pages branch.
  4. Use the gh-pages npm package:
    npm install -D gh-pages
    

    Add to frontend/package.json scripts:

    "deploy": "gh-pages -d dist"
    

    Then run:

    npm run build && npm run deploy
    

Note: GitHub Pages only serves static files. You need a separate backend host.

Backend:

  1. Create a Render account
  2. New β†’ Web Service β†’ connect your GitHub repo
  3. Root directory: backend
  4. Build command: npm install && npm run build
  5. Start command: node dist/index.js
  6. Add environment variable: JWT_SECRET=your-secret-here

Frontend:

  1. New β†’ Static Site β†’ connect same repo
  2. Root directory: frontend
  3. Build command: npm install && npm run build
  4. Publish directory: dist
  5. Add environment variable: VITE_API_URL=https://your-backend.onrender.com

Option C: Railway (One-Click)

  1. Go to railway.app
  2. New Project β†’ Deploy from GitHub β†’ select this repo
  3. Add two services: one for backend/, one for frontend/
  4. Set environment variables as above
  5. Railway auto-detects Node.js and deploys both

Option D: Vercel (Frontend) + Render (Backend)

  1. Import the repo into Vercel
  2. Set root directory to frontend
  3. It auto-detects Vite and deploys
  4. Set VITE_API_URL environment variable to your Render backend URL

Environment Variables

Backend (backend/.env)

Variable Default Description
JWT_SECRET change-me-in-production JWT signing secret
PORT 3001 Server port

Frontend

Variable Default Description
VITE_API_URL http://localhost:3001 Backend API base URL

Resetting Data


Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Commit changes: git commit -m "feat: add my feature"
  4. Push: git push origin feature/my-feature
  5. Open a Pull Request

License

MIT