Skip to content

Advanced-computer-lab-2024/WanderQuest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Typing SVG

WanderQuest

Table of Contents

  1. πŸš€ Motivation
  2. 🧱 Build Status
  3. 🎨 Code Style
  4. βš’οΈ Tech and Frameworks used
  5. πŸ”₯ Features & Screenshots
  6. πŸ’» Code Examples
  7. βš™οΈ Installation
  8. πŸ“š API Reference
  9. πŸ§ͺ Tests
  10. πŸ§‘πŸ»β€πŸ« How to Use
  11. 🀝 Contribute
  12. ©️ Credits
  13. πŸ“œ License

πŸš€ Motivation

Welcome to WanderQuest, your ultimate travel companion designed to transform vacation planning into an effortless and unforgettable experience! Whether you're longing for serene beaches, historic landmarks, or thrilling family adventures, our platform caters to every travel dream.

🧱 Build Status

example workflow

  • This project is under development and should not be used in a production settings
  • Check Issues for a list of all the reported issues
  • More automated tests should be added in the future
  • More documentation should be added

🎨 Code Style

We use Prettier to enforce a consistent code style.

Useful Commands

Useful Commands

  • Check formatting using Prettier
npm run format
  • And then fix formatting using Prettier
npm run format:fix

βš’οΈ Tech and Frameworks used

πŸ”₯ Features & Screenshots

User Registration πŸ“
  • Register as a tourist/advertiser/tour guide/seller with essential details.
  • Submit a request to register as an advertiser/tour guide/seller with professional details.
  • Upload required documents for advertiser/tour guide/seller registration.
Sign up page
User Authentication πŸ” - Login and logout securely. Sign in page
Administrator Functions πŸ‘©β€πŸ’Ό
  • Add/remove another administrator.
  • Add/remove a tourism governor.
  • Manage all users.
  • Add/edit/remove/view products/activities/itineraries/categories/tags.
  • Archive/unarchive products.
  • Accept or reject advertiser/tour guide/seller registration requests.
  • View information uploaded by advertiser/tour guide/seller.
  • View complaints.
  • Mark a complaint as pending or resolved or reply to it.
  • Create/delete/view promocodes.
  • Search/Filter/Sort for a product based on product name/price/ratings.
  • Advanced analytics or dashboards showing trends
Admin Home Page Add admin Admin complaints Admin delete account Admin Promo Code Admin requests Preference Tags
Account Management πŸ”„
  • Change password.
  • Reset forgotten password via email.
  • Request to delete account.

Account Management

Seller FunctionsπŸ›οΈ
  • Accept Terms and Conditions.
  • Create/Read/Update their profile with their information including name and description. If accepted on the system.
  • View a list of all available products.
  • Search/Filter/Sort for a product based on product name/price/ratings.
  • Add/Edit/View a product with its details, price and available quantity.
  • Upload a picture.
  • View/Filter sales report
  • Archive/unarchive products.
  • Search/Filter/Sort for a product based on product name/price/ratings.
  • Detailed performance analytics
Seller home page
Advertiser FunctionsπŸ“’
  • Accept Terms and Conditions.
  • Create/Read/Update their profile with their information. If accepted on the system.
  • View a list of all advertisers.
  • Create/update/delete activities.
  • View created activities.
  • Create/view transportation posts.
  • Get/mark as read notifications.
  • Analytics to track the performance of activities or posts
Advertiser Home page
Tourist Functions🌍
  • Read/Update their profile with their information.
  • Book trips.
  • Pay for bookings using wallet or credit card.
  • Add to/remove from/view wishlist.
  • View saved events.
  • View all orders.
  • Issue/cancel an order.
  • View available products/ upcoming activities/itineraries/places.
  • Search/Filter/Sort for a product based on product name/price/ratings.
  • Rate/review a product.
  • Redeem points/promocode.
  • File a complaint.
  • View my complaints/level/available points.
  • Change preferred currency.
  • Manage notifications.
  • Be notified/request to be notified for when a saved event is open for bookings.
  • Be reminded of your Booked Events getting Within 4 days of check.
  • Recieve a promocode on your birthday in notifications.
  • View/add/remove/edit/checkout to/from cart.
  • Cancelation policies or refund requests tied to bookings.
  • Wallet management, such as transaction history or adding funds to the wallet.
  • Save/bookmark specific promocodes or offers.
Tourist Home page Historical Places My bookings Tourist Transportation
Tour Guide FunctionsπŸ—ΊοΈ
  • Accept Terms and Conditions.
  • Create/Read/Update their profile with their information. If accepted on the system.
  • View a list of all advertisers.
  • Create/update/delete/view/activate/deactivate itineraries.
  • Rate/comment on tour guide.
  • Manage notifications.
Tour Guide home page Tour guide sales report
Tourism Governor FunctionsπŸ›οΈ
  • Create/update/delete/view places.
  • Add/view tags.

πŸ’» Code Examples

FE Admin Dashboard Routes Example
        <ul>
            <li>
              <Link href="/admin/Requests">Users Management</Link>
            </li>
            <li>
              <Link href="/admin/deleteAccount">Delete Account</Link>
            </li>
            <li>
              <Link href="/admin/addGovernor">Add Tourism Governor</Link>
            </li>
            <li>
              <Link href="/admin/addAdmin">Add Admin</Link>
            </li>
            <li>
              <Link href="/admin/editprod">Add Product</Link>
            </li>
            <li>
              <Link href="/admin/complaints">Complaints</Link>
            </li>
            <li>
              <Link href="/admin/promoCodes">Create Promocode</Link>
            </li>
            <li>
              <Link href="/admin/prefTags">Preference Tags</Link>
            </li>
            
          </ul>
BE Authentication Routes
router.post('/register', registerUser);

router.post('/login', login);

router.get('/user', requireAuth(), getUser);

router.post('/changePassword', requireAuth(), changePassword);

router.post('/uploadDocuments', requireAuth(), uploadDocuments);

router.get('/getDocuments/:id', requireAuth(), getUserDocuments);

router.get('/getUsersRequestingAcceptance', requireAuth({ role: 'Admin' }), getUsersRequestingAcceptance);

router.get('/getDocumentByFileID/:id', requireAuth(), getDocumentByFileID);

router.patch('/acceptUser/:id', requireAuth({ role: 'Admin' }), acceptUser);

router.patch('/acceptTerms', requireAuth(), acceptTerms);

router.patch('/requestAccountDeletion', requireAuth(), requestAccountDeletion);

router.post('/requestForgetPasswordEmail', requestForgetPasswordEmail);

router.post('/resetPassword', resetPassword);

router.post('/logout', logout);
BE Promocode Creation Controller
const createPromo = async (req, res) => {
  const { code, type, discount, birthday, touristId } = req.body;
  const admin = req.user._id;
  const expiry = Date.now() + (7 * 24 * 60 * 60 * 1000);
  // Validate input
  if (!code || !type || !discount) {
      return res.status(400).json({ error: ' fields are required' });
  }
  try {
      // Checking if the username already exists
      const existingPromo = await PromoCode.findOne({ code });

      if (existingPromo) {
          return res.status(400).json({ error: 'Promocode already exists' });
      }

      const promocode = await PromoCode.create({
          code,
          type,
          discount,
          expiryDate: expiry,
          createdBy: admin
      });
      const tourists = await Tourist.find();

      // Create notifications for each tourist
      const notifications = tourists.map(tourist => ({
          userID: tourist._id,
          message: `New promo code available: ${code}`,
          reason: 'New Promo Code',
          ReasonID: promocode._id // Optional reference to the promo code
      }));

      // Insert all notifications at once
      await NotificationModel.insertMany(notifications);

      res.status(200).json(promocode)

  } catch (error) {
      res.status(400).json({ error: error.message })
  }
};
BE Promocode Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const promoCodeSchema = new Schema({
    code: { type: String, required: true, unique: true },
    type: { type: String, enum: ['PERCENTAGE', 'FIXED'], required: true },
    discount: { type: Number, required: true },
    expiryDate: { type: Date, required: true },
    createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'Admin', required: false },
    birthday: { type: Boolean, required: false },
    touristId: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "Tourist",
        required: false,
        default:null,
        validate: {
            validator: function (value) {
                return !this.birthday || (this.birthday && value);
            },
            message: 'touristId is required to create a birthday promocode'
        }
    }
}, { timestamps: true });

const PromoCode = mongoose.model('PromoCode', promoCodeSchema);
module.exports = {PromoCode};
BE Promocode Applier in Payment
async function applyPromoCodes(userId, amount) {
  try {
      const user = await User.findById(userId);

      if (!user || !user.activePromoCodes || user.activePromoCodes.length === 0) {
          console.log('No active promo codes found for this user.');
          return amount; // Return original amount if no promo codes
      }

      let finalAmount = amount;

      for (const promo of user.activePromoCodes) {
          switch (promo.type) {
              case 'FIXED':
                  const fixedDiscount = await convertCurrency(promo.discount, 'USD', user.preferredCurrency);
                  finalAmount = Math.max(0, finalAmount - fixedDiscount);
                  break;

              case 'PERCENTAGE':
                  finalAmount = Math.max(0, finalAmount - (finalAmount * promo.discount) / 100);
                  break;

              default:
                  console.log('Unknown promo type:', promo.type);
          }
      }

      user.activePromoCodes = [];
      await user.save();

      return finalAmount;
  } catch (error) {
      console.error('Error applying promo codes:', error);
      throw error;
  }
}
BE Deduction from Wallet Helper
  TouristSchema.methods.deduceFromWallet = async function (amount) {
  try {
      if (amount > this.wallet) {
          throw new Error('Insufficient wallet balance');
      }
      this.wallet -= amount;
      let pointsEarned;
      switch (this.level) {
          case 1:
              pointsEarned = amount * 0.5;
              break;
          case 2:
              pointsEarned = amount * 1;
              break;
          case 3:
              pointsEarned = amount * 1.5;
              break;
          default:
              pointsEarned = 0;
              break;
      }
      this.totalPoints += pointsEarned;
      this.availablePoints += pointsEarned;
      // await sendEmail(this.email,'Payment regarding WanderQuest',`${amount} has been deducted from your wallet`);
      await this.save();
  } catch (error) {
      console.error('Error deducting from wallet:', error);
      throw error; // Re-throw the error to be handled by the caller
  }
}

βš™οΈ Installation

  • Make sure you have Node and Git installed
mkdir WanderQuest
cd WanderQuest
  • Clone this repo
git clone https://github.com/Advanced-computer-lab-2024/WanderQuest.git
  • Install dependencies
cd WanderQuest
npm install
  • How to run: Add a .env in the backend of this repo WanderQuest
PORT=4000
MONGO_URI=mongodb+srv://wndrqstaclproj:[email protected]/?retryWrites=true&w=majority&appName=WanderQuest
SECRET=thisisatestsecretcode1234!
EXCHANGE_RATE_API_KEY=878b382f87f70b368b1a1b77
SMTP_HOST=smtp-relay.brevo.com
SMTP_PORT=587
[email protected]
SMTP_PASS=xsmtpsib-f4616267d504380fe69fed5abead6b1cca0de777b8b51ca4e11529084c48d7d0-Egz8brFnH0tZ1a9q
[email protected]
STRIPE_SECRET_KEY=rk_test_51QRfekFYbqa6jLuacYBGvdPJNTTSb5JIjiHUaNFnFzC2OpONxNoMy8QlE3tEVFP4fwnKo2hUfaburyCbjjWoDWWN00M07wztsy
  • Start Front-End
cd Front-End
cd wanderquest
npm run dev
  • Start Back-End in a different terminal
cd Back-End
npm run dev

πŸ“š API References

API 1: Tourist Registration

POST: http://localhost:4000/auth/register

Request Body

{
    "username": "johndoe",
    "email": "[email protected]",
    "password": "Password123!",
    "role": "tourist",
    "nationality": "Egyptian",
    "mobileNumber": "+201234567890",
    "dob": "1990-01-01",
    "job": "Engineer"
}

Success Response (201)

{
    "userId": "675661f5f97bdd3f05225196",
    "username": "johndoe",
    "role": "tourist",
    "accepted": true
}
API 2: Tour Guide Registration

POST: http://localhost:4000/auth/register

Request Body

{
    "username": "guidejohn",
    "email": "[email protected]",
    "password": "Guide123!",
    "role": "tourGuide",
    "yearsOfExperience": 5,
    "mobileNumber": "+201234567891",
    "previousWork": ["Pyramids Tours", "Nile Cruises"]
}

Success Response (201)

{
    "userId": "675661f5f97bdd3f05225197",
    "username": "guidejohn",
    "role": "tourGuide",
    "accepted": false
}
API 3: Create Activity

POST: http://localhost:4000/advertiser/activity

Request Body

{
    "title": "Desert Safari",
    "description": "Experience the thrill of desert adventure",
    "price": 150,
    "category": "675661f5f97bdd3f05225198",
    "location": "Dubai Desert",
    "date": "2024-12-25",
    "time": "14:00",
    "capacity": 20,
    "tags": ["675661f5f97bdd3f05225199", "675661f5f97bdd3f05225200"]
}

Success Response (201)

{
    "activityId": "675661f5f97bdd3f05225201",
    "title": "Desert Safari",
    "price": 150,
    "capacity": 20,
    "createdBy": "675661f5f97bdd3f05225202"
}
API 4: Create Product

POST: http://localhost:4000/seller/addProduct

Request Body

{
    "name": "Traditional Scarf",
    "price": 299.99,
    "description": "Handmade Egyptian cotton scarf",
    "availableAmount": 50,
    "picture": {
        "filename": "scarf.jpg",
        "contentType": "image/jpeg",
        "fileID": "675661f5f97bdd3f05225203"
    }
}

Success Response (201)

{
    "productId": "675661f5f97bdd3f05225204",
    "name": "Traditional Scarf",
    "price": 299.99,
    "seller": "675661f5f97bdd3f05225205"
}
API 5: Create Booking

POST: http://localhost:4000/booking/activity

Request Body

{
    "bookingType": "activity",
    "activityId": "675661f5f97bdd3f05225201",
    "paid": false,
    "startDate": "2024-12-25",
    "details": {
        "numberOfParticipants": 2,
        "specialRequests": "Vegetarian meals"
    }
}

Success Response (201)

{
    "bookingId": "675661f5f97bdd3f05225206",
    "status": "booked",
    "totalAmount": 300
}
API 6: Create Order

POST: http://localhost:4000/tourist/cart/checkout

Request Body

{
    "products": [
        {
            "productId": "675661f5f97bdd3f05225204",
            "quantity": 2
        }
    ],
    "deliveryAddress": "675661f5f97bdd3f05225207"
}

Success Response (201)

{
    "orderId": "675661f5f97bdd3f05225208",
    "totalPrice": 599.98,
    "status": "pending",
    "paymentStatus": "pending"
}
API 7: Process Payment

POST: http://localhost:4000/payment/handleBookingPayment

Request Body

{
    "bookingId": "675661f5f97bdd3f05225206",
    "amount": 300,
    "currency": "EGP",
    "method": "wallet"
}

Success Response (200)

{
    "paymentId": "675661f5f97bdd3f05225209",
    "status": "completed",
    "paidAmount": 300
}
API 8: Add Delivery Address

POST: http://localhost:4000/tourist/addDeliveryAddresses

Request Body

{
    "street": "123 Main St",
    "city": "Cairo",
    "state": "Cairo Governorate",
    "postalCode": "11511",
    "country": "Egypt",
    "googleMapsUrl": "https://maps.google.com/?q=30.0444,31.2357"
}

Success Response (201)

{
    "addressId": "675661f5f97bdd3f05225207",
    "message": "Delivery address added successfully"
}
API 9: File Complaint

POST: http://localhost:4000/tourist/fileComplaint

Request Body

{
    "title": "Late Tour Guide",
    "body": "The tour guide was 30 minutes late for the scheduled tour",
    "date": "2024-01-15T10:30:00.000Z"
}

Success Response (201)

{
    "complaintId": "675661f5f97bdd3f05225210",
    "status": "Pending",
    "createdAt": "2024-01-15T10:30:00.000Z"
}
API 10: Rate Activity

POST: http://localhost:4000/tourist/activity/rate/:id

Request Body

{
    "rating": 4,
    "comment": "Great experience, very well organized",
    "touristId": "675661f5f97bdd3f05225196"
}

Success Response (200)

{
    "activityId": "675661f5f97bdd3f05225201",
    "newAverageRating": 4.5,
    "totalRatings": 15
}
API 11: Create Itinerary

POST: http://localhost:4000/tourGuide/create

Request Body

{
    "title": "Cairo Historical Tour",
    "description": "Explore ancient Egyptian history",
    "activities": ["675661f5f97bdd3f05225201", "675661f5f97bdd3f05225202"],
    "price": 2500,
    "duration": 5,
    "maxParticipants": 15,
    "startDates": ["2024-02-01", "2024-02-15"]
}

Success Response (201)

{
    "itineraryId": "675661f5f97bdd3f05225211",
    "title": "Cairo Historical Tour",
    "tourGuideId": "675661f5f97bdd3f05225197",
    "status": "active"
}
API 12: Create Promo Code

POST: http://localhost:4000/admin/promo

Request Body

{
    "code": "SUMMER2024",
    "type": "PERCENTAGE",
    "discount": 15,
    "expiryDate": "2024-08-31T23:59:59.999Z",
    "birthday": false
}

Success Response (201)

{
    "promoId": "675661f5f97bdd3f05225212",
    "code": "SUMMER2024",
    "status": "active",
    "createdAt": "2024-01-15T10:30:00.000Z"
}
API 13: Book Transportation

POST: http://localhost:4000/booking/transportation

Request Body

{
    "bookingType": "transportation",
    "details": {
        "transportationId": "675661f5f97bdd3f05225200",
        "passengers": 2,
        "luggageCount": 3
    },
    "paid": false,
    "startDate": "2024-02-01T09:00:00.000Z"
}

Success Response (201)

{
    "bookingId": "675661f5f97bdd3f05225213",
    "status": "booked",
    "totalAmount": 100
}
API 14: Update User Profile

PUT: http://localhost:4000/tourist/profile

Request Body

{
    "mobileNumber": "+201234567892",
    "nationality": "American",
    "job": "Software Engineer",
    "email": "[email protected]"
}

Success Response (200)

{
    "userId": "675661f5f97bdd3f05225196",
    "message": "Profile updated successfully",
    "updatedFields": ["mobileNumber", "nationality", "job", "email"]
}
API 15: View Sales Report

GET: http://localhost:4000/seller/salesReport

Response Body

{
    "totalRevenue": 15000,
    "totalSales": 50,
    "productDetails": [
        {
            "productId": "675661f5f97bdd3f05225204",
            "name": "Traditional Scarf",
            "sales": 20,
            "revenue": 5999.80
        }
    ],
    "periodStart": "2024-01-01T00:00:00.000Z",
    "periodEnd": "2024-01-31T23:59:59.999Z"
}
API 16: Get User Notifications

GET: http://localhost:4000/tourist/notifs

Response Body

{
    "notifications": [
        {
            "_id": "675661f5f97bdd3f05225214",
            "message": "Your booking has been confirmed",
            "reason": "booking_confirmation",
            "ReasonID": "675661f5f97bdd3f05225206",
            "seen": false,
            "createdAt": "2024-01-15T10:30:00.000Z"
        }
    ],
    "unreadCount": 1
}
API 17: Rate Tour Guide

POST: http://localhost:4000/tourGuide/rate/:tourGuideId

Request Body

{
    "rating": 5,
    "comment": "Excellent knowledge and communication skills",
    "touristId": "675661f5f97bdd3f05225196"
}

Success Response (200)

{
    "tourGuideId": "675661f5f97bdd3f05225197",
    "newAverageRating": 4.8,
    "totalRatings": 25
}
API 18: Create Place

POST: http://localhost:4000/tourGoverner/addPlace

Request Body

{
    "title": "Great Pyramids of Giza",
    "description": "One of the Seven Wonders of the Ancient World",
    "location": "Al Haram, Giza Governorate",
    "openingHours": "8:00 AM - 5:00 PM",
    "ticketPrices": [400, 200, 100],
    "tags": [
        { "type": "Historical" },
        { "type": "UNESCO" }
    ],
    "pictures": ["base64EncodedImage1", "base64EncodedImage2"]
}

Success Response (201)

{
    "placeId": "675661f5f97bdd3f05225215",
    "title": "Great Pyramids of Giza",
    "message": "Place added successfully"
}

πŸ§ͺ Test Routes

Test 1: User Registration Flow

POST: http://localhost:4000/auth/register

Test Cases:

{
    "validCase": {
        "input": {
            "username": "testuser",
            "email": "[email protected]",
            "password": "Password123",
            "role": "tourist"
        },
        "expectedResponse": {
            "status": 201,
            "body": {
                "message": "Registration successful"
            }
        }
    },
    "invalidCase": {
        "input": {
            "username": "test",
            "email": "invalid-email",
            "password": "123"
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid input data"
            }
        }
    }
}
Test 2: Authentication Flow

POST: http://localhost:4000/auth/login

Test Cases:

{
    "validLogin": {
        "input": {
            "username": "testuser",
            "password": "Password123"
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "token": "jwt_token"
            }
        }
    },
    "invalidLogin": {
        "input": {
            "username": "testuser",
            "password": "wrongpass"
        },
        "expectedResponse": {
            "status": 401,
            "body": {
                "error": "Invalid credentials"
            }
        }
    }
}
Test 3: Activity Booking Flow

POST: http://localhost:4000/booking/activity

Test Cases:

{
    "validBooking": {
        "input": {
            "activityId": "675661f5f97bdd3f05225197",
            "date": "2024-12-25",
            "participants": 2
        },
        "expectedResponse": {
            "status": 201,
            "body": {
                "bookingId": "675661f5f97bdd3f05225198"
            }
        }
    },
    "invalidBooking": {
        "input": {
            "activityId": "675661f5f97bdd3f05225197",
            "participants": 100
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Insufficient capacity"
            }
        }
    }
}
Test 4: Payment Processing Flow

POST: http://localhost:4000/payment/handleBookingPayment

Test Cases:

{
    "validPayment": {
        "input": {
            "bookingId": "675661f5f97bdd3f05225198",
            "amount": 200,
            "method": "wallet"
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "transactionId": "675661f5f97bdd3f05225199"
            }
        }
    },
    "insufficientFunds": {
        "input": {
            "bookingId": "675661f5f97bdd3f05225198",
            "amount": 10000,
            "method": "wallet"
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Insufficient funds"
            }
        }
    }
}
Test 5: Cart Management Flow

POST: http://localhost:4000/tourist/cart/add

Test Cases:

{
    "addToCart": {
        "input": {
            "productId": "675661f5f97bdd3f05225196",
            "quantity": 2
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "message": "Added to cart"
            }
        }
    },
    "invalidQuantity": {
        "input": {
            "productId": "675661f5f97bdd3f05225196",
            "quantity": -1
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid quantity"
            }
        }
    }
}
Test 6: Itinerary Creation Flow

POST: http://localhost:4000/tourGuide/create

Test Cases:

{
    "validItinerary": {
        "input": {
            "title": "Egypt Explorer",
            "activities": ["675661f5f97bdd3f05225197"],
            "duration": 7,
            "price": 1500
        },
        "expectedResponse": {
            "status": 201,
            "body": {
                "itineraryId": "675661f5f97bdd3f05225200"
            }
        }
    },
    "invalidItinerary": {
        "input": {
            "title": "",
            "duration": -1
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid itinerary data"
            }
        }
    }
}
Test 7: Rating System Flow

POST: http://localhost:4000/tourist/activity/rate/:id

Test Cases:

{
    "validRating": {
        "input": {
            "rating": 5,
            "comment": "Great experience!"
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "newAverageRating": 4.5
            }
        }
    },
    "invalidRating": {
        "input": {
            "rating": 6,
            "comment": ""
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid rating value"
            }
        }
    }
}
Test 8: Profile Update Flow

PUT: http://localhost:4000/tourist/profile

Test Cases:

{
    "validUpdate": {
        "input": {
            "name": "John Doe",
            "phone": "+1234567890"
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "message": "Profile updated"
            }
        }
    },
    "invalidUpdate": {
        "input": {
            "phone": "invalid-phone"
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid phone format"
            }
        }
    }
}
Test 9: Complaint System Flow

POST: http://localhost:4000/tourist/fileComplaint

Test Cases:

{
    "validComplaint": {
        "input": {
            "subject": "Booking Issue",
            "description": "Activity cancelled"
        },
        "expectedResponse": {
            "status": 201,
            "body": {
                "complaintId": "675661f5f97bdd3f05225201"
            }
        }
    },
    "invalidComplaint": {
        "input": {
            "subject": ""
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Subject required"
            }
        }
    }
}
Test 10: Notification System Flow

GET: http://localhost:4000/tourist/notifs

Test Cases:

{
    "validRequest": {
        "expectedResponse": {
            "status": 200,
            "body": {
                "notifications": [
                    {
                        "message": "Booking confirmed",
                        "seen": false
                    }
                ]
            }
        }
    }
}
Test 11: Promo Code Flow

POST: http://localhost:4000/tourist/redeemCode

Test Cases:

{
    "validPromo": {
        "input": {
            "code": "SUMMER2024",
            "orderId": "675661f5f97bdd3f05225203"
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "discountAmount": 50
            }
        }
    },
    "invalidPromo": {
        "input": {
            "code": "INVALID"
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid promo code"
            }
        }
    }
}
Test 12: Transportation Booking Flow

POST: http://localhost:4000/booking/transportation

Test Cases:

{
    "validBooking": {
        "input": {
            "transportationId": "675661f5f97bdd3f05225204",
            "seats": 2,
            "date": "2024-12-25"
        },
        "expectedResponse": {
            "status": 201,
            "body": {
                "bookingId": "675661f5f97bdd3f05225205"
            }
        }
    },
    "invalidBooking": {
        "input": {
            "seats": -1
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid seats number"
            }
        }
    }
}
Test 13: User Statistics Flow

GET: http://localhost:4000/admin/userStats

Test Cases:

{
    "validRequest": {
        "expectedResponse": {
            "status": 200,
            "body": {
                "totalUsers": 1000,
                "newUsersPerMonth": [
                    {
                        "month": "January",
                        "count": 50
                    }
                ]
            }
        }
    }
}
Test 14: Activity Creation Flow

POST: http://localhost:4000/advertiser/activity

Test Cases:

{
    "validActivity": {
        "input": {
            "title": "Desert Safari",
            "price": 100,
            "capacity": 20
        },
        "expectedResponse": {
            "status": 201,
            "body": {
                "activityId": "675661f5f97bdd3f05225206"
            }
        }
    },
    "invalidActivity": {
        "input": {
            "price": -100
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid price"
            }
        }
    }
}
Test 15: Password Reset Flow

POST: http://localhost:4000/auth/resetPassword

Test Cases:

{
    "validReset": {
        "input": {
            "email": "[email protected]",
            "otp": "123456",
            "newPassword": "NewPassword123"
        },
        "expectedResponse": {
            "status": 200,
            "body": {
                "message": "Password reset successful"
            }
        }
    },
    "invalidReset": {
        "input": {
            "email": "[email protected]",
            "otp": "wrong-otp"
        },
        "expectedResponse": {
            "status": 400,
            "body": {
                "error": "Invalid OTP"
            }
        }
    }
}

πŸ§ͺ Tests

We use Postman to manually test all our api references by making sure the response is as expected.

image

πŸ§‘πŸ»β€πŸ« How to Use

Make sure to follow the Installation steps first

Tourist 🌍

Sign Up & Profile Management:

  • Register with email, username, password, mobile number, nationality, DOB, and occupation.
  • Update your profile, including wallet information and vacation preferences (historic areas, beaches, shopping, etc.).

Planning Your Vacation:

  • Search for specific museums, activities, or itineraries by name, category, or tag.
  • Filter activities and itineraries by budget, date, category, preferences, or language.
  • Sort upcoming events or itineraries by price or ratings.

Booking & Payments:

  • Book flights, hotels, transportation, and tickets to events directly through the app.
  • Pay online via credit/debit card (Stripe) or wallet balance.
  • Receive payment receipts via email.

Personalized Experience:

  • Bookmark events to view later or request notifications when bookings open.
  • Redeem loyalty points for wallet cash and earn badges based on your level.

Ratings & Feedback:

  • Rate and comment on events, activities, or itineraries you participated in.
  • Rate and review your tour guide.

Notifications & Updates:

  • Get reminders for upcoming bookings via app and email.
  • View all your upcoming and past paid activities.

Cancellations & Refunds:

  • Cancel bookings 48 hours before the event to receive a wallet refund.

Complaints & Support:

  • File complaints with title, description, and date for admin review.
Tour Guide πŸ—ΊοΈ

Sign Up & Profile Management:

  • Register with email, username, and password.
  • Upload required documents for admin approval.
  • Create or update your profile with personal details, experience, and work history.

Itinerary Management:

  • Create, read, update, or delete itineraries with details like activities, locations, timeline, price, accessibility, and language.
  • Activate/deactivate itineraries with bookings.

Analytics & Sales:

  • View a sales report with revenue from your itineraries.
  • Filter sales reports by itinerary, date, or month.
  • View a report of tourists using your itineraries and filter by month.

Notifications:

  • Receive alerts if an itinerary is flagged as inappropriate.
  • Get notified of bookings or cancellations for your itineraries.
Advertiser πŸ“’

Sign Up & Profile Management:

  • Register with email, username, and password.
  • Upload required documents for admin approval.
  • Create or update your profile with company details like website, hotline, and company profile.

Activity Management:

  • Create, read, update, or delete activities with details like date, time, location, price, category, tags, and discounts.
  • View a list of all your created activities.

Analytics & Sales:

  • View a sales report with revenue from your activities.
  • Filter sales reports by activity, date, or month.
  • View a report of tourists attending your activities and filter by month.

Notifications:

  • Receive alerts if an activity is flagged as inappropriate.
  • Get notified of bookings or cancellations for your activities.
Seller πŸ›οΈ

Sign Up & Profile Management:

  • Register with email, username, and password.
  • Upload required documents for admin approval.
  • Create or update your profile with name and description of your store.

Gift Shop Management:

  • Add and manage products in the in-app gift shop.
  • View sales reports for your store.
  • Filter sales reports by product, date, or month.
Tourism Governor πŸ›οΈ

Sign Up & Management:

  • Create museums and historical places with details like description, pictures, location, hours, and ticket prices.
  • Create tags for categorizing historical places (e.g., type, historical period).
  • Update or delete museums and tags as needed.

Overview:

  • View a list of all museums and historical places you’ve created.
Administrator πŸ‘©β€πŸ’Ό

User Management:

  • Accept or reject registration requests for tour guides, advertisers, and sellers based on uploaded documents.
  • Add or remove other admins and tourism governors.
  • View the total number of users and monthly new user stats.

Content Management:

  • Create, read, update, or delete activity categories and preference tags.
  • Flag events or itineraries deemed inappropriate.

Complaint Management:

  • View and manage complaints from users.
  • Mark complaints as pending, resolved, or reply directly.

Analytics & Reports:

  • View and filter sales reports by product, date, or month.
  • Access a comprehensive revenue report for events, itineraries, and gift shop sales.

Make sure to check out the πŸ”₯ Features & Screenshots !

🀝 Contribute

We welcome contributions to WanderQuest. If you want to contribute, it's as easy as:

  1. Fork the repo
  2. Create a new branch (git checkout -b my-new-feature)
  3. Make changes
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request
  7. Wait for your PR to be reviewed and merged

NOTE

We welcome all contributions, but please make sure to follow our code style and linting rules. You can check the Code Style section for more details.

🫑 Credits

Docs

YouTube Videos

πŸ“œ License

The software is open source under the Apache 2.0 License.

Apache 2.0

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published