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
13 changes: 13 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Code of Conduct

We are committed to fostering a welcoming and inclusive community. All participants are expected to abide by this code of conduct.

- Be respectful and considerate.
- Use inclusive language.
- No harassment, trolling, or personal attacks.
- Respect differing viewpoints and experiences.
- Gracefully accept constructive criticism.

If you experience or witness unacceptable behavior, please report it to the maintainers via GitHub issues or contact listed in the repository.

This project is open source and follows the spirit of the Contributor Covenant.
73 changes: 73 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Contributing to QuickStay (Hotel-Booking)

Thanks for your interest in contributing! This guide walks you through the setup, coding standards, and pull request process. New contributors are welcome — issues labeled with good first issue or gssoc 25 are great starting points.

## Quick Start

1. Fork the repo on GitHub.
2. Clone your fork:
- HTTPS: `git clone https://github.com/<your-username>/Hotel-Booking.git`
3. Add the upstream remote:
- `git remote add upstream https://github.com/manishkumar8312/Hotel-Booking.git`
4. Create a feature branch:
- `git checkout -b docs/add-env-examples` (use a descriptive name)

## Local Setup

- Requirements:
- Node.js 18+ (20+ recommended)
- npm 9+
- MongoDB (local or Atlas)

- Install and run:
- Backend
- `cd server`
- `npm install`
- Copy env: `cp .env.example .env` and fill values
- `npm run server` (defaults to http://localhost:3000)
- Frontend
- `cd client`
- `npm install`
- Copy env: `cp .env.example .env` and fill values
- `npm run dev` (defaults to http://localhost:5173)

## Environment Variables

- Templates are provided in `server/.env.example` and `client/.env.example`.
- Never commit real secrets. `.env` is already gitignored.

## Coding Standards

- Lint: `npm run lint` (from client/)
- Prefer Conventional Commits for messages, e.g.
- `feat: add hotel rating component`
- `fix: resolve navbar overlap on mobile`
- `docs: align env examples with README`
- Keep PRs focused and small when possible.

## Commit & PR Process

1. Ensure your branch is up to date:
- `git fetch upstream` ; `git rebase upstream/main`
2. Commit changes with clear messages.
3. Push to your fork:
- `git push -u origin <branch-name>`
4. Open a Pull Request targeting `main` of the upstream repo.
5. In the PR description, include:
- What/why of the change
- Screenshots for UI changes (before/after)
- Linked issue: `Closes #<issue-number>`

## Issue Types You Can Pick

- docs: Improving README, adding CONTRIBUTING, CODE_OF_CONDUCT, LICENSE
- bug: UI/UX polish (e.g., mobile overlaps), 404 handling, minor runtime fixes
- feat: Small features (e.g., simple client-side validation)
- perf: Minor optimizations (e.g., memoization)

## Communication

- Be respectful and follow our Code of Conduct.
- If unsure, open an issue or draft PR to discuss.

Happy contributing! 💙
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 QuickStay contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ QuickStay/
```bash
cd server
npm install
npm run server # Starts Express backend using nodemon
npm run server # Starts Express backend using nodemon (default http://localhost:3000)
```

### 🌐 Frontend (Client)

```bash
cd client
npm install
npm start # Starts React frontend on http://localhost:3000
npm run dev # Starts Vite dev server (defaults to http://localhost:5173)
```

---
Expand All @@ -87,19 +87,20 @@ Create `.env` files in both `server/` and `client/` with the following:
### For Server

```
PORT=5000
MONGO_URI=your_mongodb_uri
PORT=3000
MONGODB_URI=your_mongodb_connection_string # e.g. mongodb://localhost:27017
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
CLERK_SECRET_KEY=your_clerk_secret
CLERK_WEBHOOK_SECRET=your_clerk_webhook_secret
```

### For Client

```
VITE_CLERK_PUBLISHABLE_KEY=your_clerk_key
VITE_API_BASE_URL=http://localhost:5000/api
VITE_API_BASE_URL=http://localhost:3000/api
```

---
Expand Down Expand Up @@ -129,7 +130,16 @@ VITE_API_BASE_URL=http://localhost:5000/api
Feel free to fork this project and raise a Pull Request.

```bash
git clone https://github.com/manishkumar8312/QuickStay.git
git clone https://github.com/manishkumar8312/Hotel-Booking.git
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed setup, coding standards, and PR process. Please follow our [Code of Conduct](CODE_OF_CONDUCT.md).

You can also use the provided `.env.example` files in both `server/` and `client/` as templates:

```
cp server/.env.example server/.env
cp client/.env.example client/.env
```

---
Expand Down
2 changes: 2 additions & 0 deletions client/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
VITE_API_BASE_URL=http://localhost:3000/api
5 changes: 2 additions & 3 deletions client/sample.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
VITE_CLERK_PUBLISHABLE_KEY=Enter_the_key
VITE_BACKEND_URL=your_backend_url
VITE_CURRENCY=your_preferred_currency
VITE_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
VITE_API_BASE_URL=http://localhost:3000/api
6 changes: 6 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import Dashboard from './pages/hotelOwner/Dashboard';
import AddRoom from './pages/hotelOwner/AddRoom';
import ListRoom from './pages/hotelOwner/ListRoom';
import HotelMap from './pages/HotelMap';
import NotFound from './pages/NotFound';
import Login from './pages/Login';
import Signup from './pages/Signup';

const App = () => {

Expand All @@ -28,11 +31,14 @@ const App = () => {
<Route path='/rooms/:id' element={<RoomDetails/>} />
<Route path='/my-bookings' element={<MyBookings/>} />
<Route path='/map' element={<HotelMap/>} />
<Route path='/login' element={<Login/>} />
<Route path='/signup' element={<Signup/>} />
<Route path='/owner' element={<Layout/>}>
<Route index element={<Dashboard/>}/>
<Route path="add-room" element={<AddRoom/>}/>
<Route path="list-room" element={<ListRoom/>}/>
</Route>
<Route path="*" element={<NotFound/>} />
</Routes>
</div>
<Footer/>
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const Navbar = (props) => {
<UserButton.MenuItems>
<UserButton.Action label="My Bookings" labelIcon={<BookIcon/>} onClick={()=> navigate('/my-bookings')}/>
</UserButton.MenuItems>
</UserButton>) : (<button onClick={openSignIn} className={`${theme === 'dark' ? 'bg-[var(--primary)] text-white px-4 py-2.5 rounded-full' : 'bg-black text-white px-8 py-2.5 rounded-full ml-4'} transition-all duration-500`}>
</UserButton>) : (<button onClick={()=> navigate('/login')} className={`${theme === 'dark' ? 'bg-[var(--primary)] text-white px-4 py-2.5 rounded-full' : 'bg-black text-white px-8 py-2.5 rounded-full ml-4'} transition-all duration-500`}>
Login
</button>)}

Expand Down Expand Up @@ -136,7 +136,7 @@ const Navbar = (props) => {
Dashboard
</button>}

{!user && <button onClick={openSignIn} className={`px-8 py-2.5 rounded-full transition-all duration-500 ${theme === 'dark' ? 'bg-[var(--primary)] text-white' : 'bg-black text-white'}`}>
{!user && <button onClick={()=> navigate('/login')} className={`px-8 py-2.5 rounded-full transition-all duration-500 ${theme === 'dark' ? 'bg-[var(--primary)] text-white' : 'bg-black text-white'}`}>
Login
</button>}
</div>
Expand Down
55 changes: 55 additions & 0 deletions client/src/pages/Login.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { SignIn, SignedIn, SignedOut, useAuth } from '@clerk/clerk-react';

const Login = () => {
const { isLoaded } = useAuth();
const key = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
const isPlaceholder = !key || key === 'pk_test_demo';

if (!isLoaded) {
return (
<div className="flex items-center justify-center min-h-[60vh]">
<div className="animate-pulse text-gray-500">Loading…</div>
</div>
);
}

return (
<div className="flex items-center justify-center py-16 min-h-[70vh]">
<div className="w-full max-w-md">
{isPlaceholder ? (
<div className="p-6 rounded-lg border bg-[var(--surface,#0b1220)] text-[var(--text,#c7d2fe)]">
<h2 className="text-xl font-semibold mb-2">Clerk not configured</h2>
<p className="text-gray-400 mb-4">Add a valid VITE_CLERK_PUBLISHABLE_KEY in <code>client/.env</code> to render the login form.</p>
<ol className="list-decimal list-inside text-gray-400 space-y-1 mb-4">
<li>Get a key from your Clerk project (Publishable Key)</li>
<li>Update <code>client/.env</code> and restart Vite</li>
</ol>
<div className="flex gap-3">
<a href="/rooms" className="px-4 py-2 rounded-md border">Browse Rooms</a>
<a href="/" className="px-4 py-2 rounded-md bg-orange-500 text-white">Go Home</a>
</div>
</div>
) : (
<>
<SignedOut>
<SignIn routing="path" path="/login" signUpUrl="/signup" />
</SignedOut>
<SignedIn>
<div className="text-center space-y-4">
<h1 className="text-2xl font-semibold">You're already signed in</h1>
<p className="text-gray-500">Continue to your dashboard or browse rooms.</p>
<div className="flex gap-3 justify-center">
<a href="/owner" className="px-4 py-2 rounded-md bg-orange-500 text-white">Owner Dashboard</a>
<a href="/rooms" className="px-4 py-2 rounded-md border">Browse Rooms</a>
</div>
</div>
</SignedIn>
</>
)}
</div>
</div>
);
};

export default Login;
24 changes: 24 additions & 0 deletions client/src/pages/NotFound.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { Link } from 'react-router-dom';

const NotFound = () => {
return (
<div className="flex flex-col items-center justify-center text-center py-24 gap-6">
<div className="text-8xl font-extrabold text-gray-300 select-none">404</div>
<h1 className="text-3xl md:text-4xl font-semibold">Page not found</h1>
<p className="text-gray-500 max-w-xl">
The page you’re looking for doesn’t exist or was moved. Check the URL or go back to a safe place.
</p>
<div className="flex flex-wrap items-center justify-center gap-3">
<Link to="/" className="px-4 py-2 rounded-md bg-orange-500 text-white hover:bg-orange-600 transition">
Go to Home
</Link>
<Link to="/rooms" className="px-4 py-2 rounded-md border border-gray-300 hover:bg-gray-100 transition">
Browse Rooms
</Link>
</div>
</div>
);
};

export default NotFound;
37 changes: 37 additions & 0 deletions client/src/pages/Signup.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { SignUp, SignedIn, SignedOut } from '@clerk/clerk-react';

const Signup = () => {
const key = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
const isPlaceholder = !key || key === 'pk_test_demo';
return (
<div className="flex items-center justify-center py-16 min-h-[70vh]">
<div className="w-full max-w-md">
{isPlaceholder ? (
<div className="p-6 rounded-lg border bg-[var(--surface,#0b1220)] text-[var(--text,#c7d2fe)]">
<h2 className="text-xl font-semibold mb-2">Clerk not configured</h2>
<p className="text-gray-400 mb-4">Add VITE_CLERK_PUBLISHABLE_KEY in client/.env to render the signup form.</p>
<div className="flex gap-3">
<a href="/rooms" className="px-4 py-2 rounded-md border">Browse Rooms</a>
<a href="/" className="px-4 py-2 rounded-md bg-orange-500 text-white">Go Home</a>
</div>
</div>
) : (
<>
<SignedOut>
<SignUp routing="path" path="/signup" signInUrl="/login" />
</SignedOut>
<SignedIn>
<div className="text-center space-y-4">
<h1 className="text-2xl font-semibold">You're already signed in</h1>
<a className="px-4 py-2 rounded-md bg-orange-500 text-white" href="/">Go Home</a>
</div>
</SignedIn>
</>
)}
</div>
</div>
);
};

export default Signup;
11 changes: 11 additions & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PORT=3000
MONGODB_URI=mongodb://localhost:27017

# Cloudinary (for image uploads)
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret

# Clerk (server-side only)
CLERK_SECRET_KEY=your_clerk_secret
CLERK_WEBHOOK_SECRET=your_clerk_webhook_secret
14 changes: 9 additions & 5 deletions server/sample.env
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
MONGODB_URI = database_uri
PORT=3000
MONGODB_URI=mongodb://localhost:27017

# Cloudinary (for image uploads)
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret

#Clerk Keys
CLERK_PUBLISHABLE_KEY=your_publishable_key
CLERK_SECRET_KEY=your_secret_key
CLERK_WEBHOOK_SECRET=your_webhook_key
# Clerk (server-side only)
CLERK_SECRET_KEY=your_clerk_secret
CLERK_WEBHOOK_SECRET=your_clerk_webhook_secret
Loading