Skip to content

Advanced-computer-lab-2024/Are-we-there-yet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Are We There Yet? Are We There Yet Logo

Table of Contents

Motivation

The "Are We There Yet?" project aims to create a virtual trip planner that simplifies the process of planning and booking trips. By leveraging modern technologies such as MongoDB, JWT, Cloudinary, and Stripe, this project provides a seamless and secure experience for users to manage their travel plans. The motivation behind this project is to offer a comprehensive solution that addresses common pain points in trip planning, such as booking management, payment processing, and document handling, all while ensuring user data security and ease of use.

Build Status

Deployment

This project is deployed on Render. You can access it at Are We There Yet.

Backend Deployment: Backend Frontend Deployment: Frontend

Possible Deployment Issues and Solutions

  • MongoDB Connection Error:

    • If you encounter a MongoDB connection error, ensure that your MongoDB connection URI is correctly configured in the .env file.
    • MongoDB does not work on Orange network, so you may need to use a different network.
  • Cloudinary Configuration Error:

    • If you face issues with Cloudinary configuration, verify that your Cloudinary URL is correctly set in the .env file.
    • Ensure that your Cloudinary account is active and has the necessary permissions to upload and manage files.
  • Testing Issues

    • Incomplete Test Coverage: If you encounter issues with test coverage, ensure that all critical components and functions are tested.
    • CI/CD requires constant updates to the test suite to ensure that new features and changes are adequately tested.
  • Missing Data On Flight or Hotel Pages

    • API limits may cause missing data on flight or hotel pages. Ensure that you have the necessary API keys and permissions to access the required data. Upgrading the API plan may help resolve this issue.
  • Deployment Issues

    • If you face deployment issues, check the deployment logs for error messages and warnings. Common deployment issues include missing dependencies, incorrect environment variables, and network connectivity problems.

    • The Free Tier of Render has limitations on the number of services and resources available.

Code Style

Prettier

This project uses Prettier for code formatting. Below is the Prettier configuration used:

{
  "tabWidth": 2,
  "printWidth": 120,
  "trailingComma": "es5",
  "arrowParens": "always",
  "semi": true,
  "singleQuote": true
}

File Structure

├── assets
│   ├── badges
│   ├── logo
│   ├── screenshots
|
├── backend
│   ├── src
│   |   ├── config
│   |   ├── constants
│   |   ├── controllers
│   |   ├── database
│   |   |   ├── models
│   |   |   ├── repositories
│   |   ├── exceptions
│   |   ├── middlewares
│   │   |   ├── auth
│   |   ├── routes
│   |   ├── services
│   |   ├── types
│   |   ├── app.ts
│   |   ├── server.ts
│   ├── tests
|   ├── .env
|   ├── .gitignore
|   ├── package.json
|   ├── tsconfig.json
|   ├── tsconfig.test.json
|
├── frontend
│   ├── public
│   ├── src
│   |   ├── components
│   |   ├── lib
│   |   ├── modules
│   │   |   ├── Activity
│   │   |   ├── etc.
├── .gitignore
├── .prettierrc
├── README.md

Backend .env template

# Server Port
PORT=8000

# MongoDB Connection URI
MONGO_URI=mongodb+srv:<username>:<password>@<cluster-url>/<database>

# JWT Token Secret
TOKEN_SECRET=your_token_secret

# Cloudinary Configuration
CLOUDINARY_URL=cloudinary://<api

STRIPE_SECRET_KEY=your_stripe_secret_key
# Email Credentials
EMAIL=your_email
PASSWORD=your_email_password

Branch naming convention

backend/root -> deployed to production
backend/dev -> where all the development happens. Our code is merged here before being deployed to production
backend/feat/feature -> where you work on your feature

frontend/root -> deployed to production
frontend/dev -> where all the development happens. Our code is merged here before being deployed to production
frontend/feat/feature -> where you work on your feature

Screenshots

ScreenShot1 ScreenShot2 ScreenShot3
ScreenShot4 ScreenShot5 ScreenShot6
ScreenShot7 ScreenShot8 ScreenShot9
ScreenShot10 ScreenShot11 ScreenShot12
ScreenShot13 ScreenShot14 ScreenShot15
ScreenShot16 ScreenShot17 ScreenShot18
ScreenShot19 ScreenShot20 ScreenShot21
ScreenShot22 ScreenShot23 ScreenShot24
ScreenShot25 ScreenShot26

Tech/Framework Used

Node.js Express React MongoDB TypeScript Tailwind CSS JWT Jest Stripe Cloudinary Nodemailer Render

Features

Guest (Non-registered User)

  • Browse and view all upcoming activities, itineraries, and historical places/museums
  • Filter activities by budget, date, category, and ratings
  • Sort activities and itineraries by price or ratings
  • Filter itineraries by budget, date, preferences, and language
  • Filter historical places/museums by tags
  • Register as a tourist (requires email, username, password, mobile number, nationality, DOB, job/student status)
  • Register as a tour guide, advertiser, or seller (requires username, email, password, and document verification)
  • Access step-by-step vacation planning guide
  • Choose activity categories
  • Search for specific museums, historical places, activities, or itineraries by name, category, or tag
  • View available products with details, prices, and reviews

Tourist

All Guest features plus:

  • Secure login with username and password
  • Password management (change password, password recovery via email OTP)
  • Profile management (view/update personal information)
  • Wallet system integration with real-time balance updates

Booking and Events

  • Book tickets for events, activities, or itineraries
  • Pay online using credit/debit cards (Stripe) or wallet
  • Receive payment receipts via email
  • Cancel bookings up to 48 hours before start time
  • View upcoming and past activities/itineraries
  • Choose preferred currency for price display
  • Bookmark events for later viewing
  • Request notifications for booking availability
  • Receive event reminders via app and email

Ratings and Reviews

  • Rate and review tour guides after completed tours
  • Rate and review itineraries after completion
  • Rate and review attended events/activities
  • Rate and review purchased products

Loyalty Program

  • Earn loyalty points on payments
  • Progress through three loyalty levels:
    • Level 1: Up to 100K points (0.5Ă— points per payment)
    • Level 2: Up to 500K points (1Ă— points per payment)
    • Level 3: Over 500K points (1.5Ă— points per payment)
  • Receive level-based badges
  • Redeem points for wallet cash (10000 points = 100 EGP)
  • Receive birthday promo codes

Shopping Features

  • View and search products by name
  • Filter products by price
  • Sort products by ratings
  • Manage wishlist (add, remove, view items)
  • Shopping cart functionality:
    • Add/remove items
    • Adjust quantities
    • Add items from wishlist
  • Multiple delivery addresses management
  • Flexible payment options (wallet, credit card, cash on delivery)
  • View order history and status
  • Cancel orders with wallet refund
  • Use promo codes

Customer Support

  • File complaints with title, description, and date
  • Track complaint status (pending/resolved)
  • View personal complaint history

Tour Guide

  • Complete profile management (similar to LinkedIn individual profiles)
  • Profile picture upload
  • Create, view, update, and delete itineraries with detailed information:
    • Activities and locations
    • Timeline and duration
    • Language options
    • Pricing
    • Available dates and times
    • Accessibility details
    • Pick-up/drop-off locations
  • Activate/deactivate itineraries
  • View all created itineraries
  • Access sales reports and revenue tracking
  • Filter sales reports by activity/itinerary/date/month
  • View tourist attendance reports
  • Receive notifications for flagged content
  • Account deletion request option

Advertiser

  • Company profile management (similar to LinkedIn company profiles)
  • Logo upload
  • Create, view, update, and delete activities with:
    • Date and time
    • Location (Google Maps integration)
    • Pricing and special discounts
    • Categories and tags
    • Booking availability
  • View all created activities
  • Access sales reports and revenue tracking
  • Filter sales reports by activity/date/month
  • View tourist attendance reports
  • Receive notifications for flagged content
  • Account deletion request option

Seller

  • Basic profile management (name and description)
  • Logo upload
  • Product management:
    • Add products with details, prices, and quantities
    • Upload product images
    • Edit product details and pricing
    • Archive/unarchive products
    • View available quantities and sales
    • Receive out-of-stock notifications
  • View sales reports
  • Filter sales reports by product/date/month
  • Account deletion request option

Tourism Governor

  • Manage museums and historical places:
    • Add descriptions and pictures
    • Set locations and opening hours
    • Configure ticket prices (foreign, native, student rates)
    • Create and manage historical location tags
  • View all created locations and places

Administrator

  • User management:
    • Add new administrators
    • Add Tourism Governors
    • Delete user accounts
    • View total user counts and new user statistics

Content management:

  • Review and verify registration documents
  • Accept/reject tour guides, advertisers, and sellers
  • Flag inappropriate events/itineraries
  • Create/manage activity categories
  • Create/manage preference tags
  • Create promo codes

Complaint Management

  • View and sort complaints by date
  • Filter complaints by status
  • View complaint details
  • Update complaint status
  • Respond to complaints

Product Management

  • Manage product listings
  • View product quantities and sales
  • Archive/unarchive products

Financial tracking:

  • View comprehensive sales reports
  • Monitor revenue from events, itineraries, and gift shop
  • Filter sales reports by product/date/month
  • Track 10% platform commission on online bookings

Code Examples

Authentication Middleware

Below is an example of an authentication middleware using Express and JWT. This middleware verifies the JWT token and attaches the user payload to the request object. It also includes a function to allow certain paths to be accessed without authentication.

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { logger } from './logger.middleware';
import { ResponseStatusCodes } from '../types/ResponseStatusCodes.types';

interface UserPayload {
  userId: string;
  accountType: string;
}

declare global {
  namespace Express {
    interface Request {
      user: UserPayload;
    }
  }
}

const authenticateToken = (req: Request, res: Response, next: NextFunction) => {
  const token = req.header('Authorization')?.split(' ')[1];

  if (!token) {
    logger.error('Access Denied');
    res.status(ResponseStatusCodes.UNAUTHORIZED).send('Access Denied');
    return;
  }

  if (req.header('Authorization')?.split(' ')[0] !== 'Bearer') {
    logger.error('Invalid Token');
    res.status(ResponseStatusCodes.UNAUTHORIZED).send('Invalid Token');
    return;
  }

  try {
    const decoded = jwt.verify(token, process.env.TOKEN_SECRET as string) as UserPayload;
    req.user = decoded;
    next();
  } catch (err) {
    logger.error('Expired Token:', err instanceof Error ? err.message : 'Unknown error');
    res.status(ResponseStatusCodes.FORBIDDEN).send('Expired Token');
  }
};

const openPaths = [
  { path: '/api/auth/register', methods: ['POST'] },
  { path: '/api/auth/login', methods: ['POST'] },
  { path: '/api/itineraries/get', methods: ['GET'] },
  { path: '/api/museums/getall', methods: ['GET'] },
  { path: '/api/activities', methods: ['GET'] },
  { path: '/api/attachments', methods: ['POST'] },
  { path: '/api/termsAndConditions', methods: ['GET'] },
  { path: '/api/tags', methods: ['GET'] },
  { path: '/api/categories', methods: ['GET'] },
  { path: '/api/users/forgotPassword', methods: ['POST'] },
  { path: '/api/users/verifyOTP', methods: ['POST'] },
];

const authenticateUnlessOpen = (req: Request, res: Response, next: NextFunction) => {
  const isOpenPath = openPaths.some((route) => route.path === req.path && route.methods.includes(req.method));

  if (isOpenPath) {
    return next();
  }

  return authenticateToken(req, res, next);
};

export { authenticateToken, authenticateUnlessOpen };

Activity Controller

import { Request, Response } from 'express';
import activityRepo from '../database/repositories/activity.repo';

const createActivity = async (req: Request, res: Response) => {
  try {
    const activity = req.body;
    activity.created_by = req.user.userId;
    const newActivity = await activityRepo.createActivity(activity);
    res.status(201).json({ message: 'Activity created successfully', data: { activityId: newActivity._id } });
  } catch (error) {
    res.status(400).json({ message: error.message, data: [] });
  }
};

export { createActivity };

React Component

Below is an example of a React component that uses the Radix UI library to create a custom select dropdown with a trigger component.

import * as React from 'react';
import * as SelectPrimitive from '@radix-ui/react-select';
import { Check, ChevronDown, ChevronUp } from 'lucide-react';

const Select = SelectPrimitive.Root;

const SelectTrigger = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
  <SelectPrimitive.Trigger
    ref={ref}
    className={`flex h-full w-full items-center justify-between rounded-md bg-background p-3 placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-accent-gold disabled:cursor-not-allowed disabled:opacity-50 ${className}`}
    {...props}
  >
    {children}
    <SelectPrimitive.Icon asChild>
      <ChevronDown className="h-4 w-4 opacity-50" />
    </SelectPrimitive.Icon>
  </SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;

export { Select, SelectTrigger };

Axios Instance

import axios from 'axios';
import { NavigateFunction } from 'react-router';

const axiosInstance = axios.create({
  baseURL: import.meta.env.VITE_BACK_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

axiosInstance.interceptors.request.use(
  (config) => {
    config.headers = config.headers || {};
    const token = localStorage.getItem('token');
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }
    const currency = localStorage.getItem('currency') || 'EGP';
    config.headers['Currency'] = currency;
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

export const setupInterceptors = (navigate: NavigateFunction) => {
  // Response Interceptor
  axiosInstance.interceptors.response.use(
    (response) => response,
    (error) => {
      if (error.response && [401, 403].includes(error.response.status)) {
        localStorage.removeItem('token');
        navigate('/register');
      }
      return Promise.reject(error);
    }
  );
};

export default axiosInstance;

Installation

  1. Clone the repository:

    git clone https://github.com/yourusername/your-repo-name.git
    cd your-repo-name
    
  2. Install dependencies:

    cd backend
    npm install
    cd ../frontend
    npm install
    
  3. Set up your .env file in the backend folder create a .env file in the backend folder and add the following:

    # Server Port
     PORT=8000
    
     # MongoDB Connection URI
     MONGO_URI=mongodb+srv:<username>:<password>@<cluster-url>/<database>
    
     # JWT Token Secret
     TOKEN_SECRET=your_token_secret
    
     # Cloudinary Configuration
     CLOUDINARY_URL=cloudinary://<api
    
     STRIPE_SECRET_KEY=your_stripe_secret_key
     # Email Credentials
     EMAIL=your_email
     PASSWORD=your_email_password
  4. Run the app:

    cd backend
    npm start
    cd ../frontend
    npm start

API References

API Documentation

Tests

This project uses Jest for unit testing. You can run the tests using the following command:

cd backend
npm run test

How to Use

  1. Sign Up / Log In:

    • Visit the website and create a new account or log in with your existing credentials.
  2. Browse Trips:

    • Explore the available trips and activities. Use the search and filter options to find trips that match your preferences.
  3. Book a Trip:

    • Select a trip and proceed to book it. Fill in the required details and make the payment using the integrated Stripe payment gateway.
  4. Manage Bookings:

    • View and manage your bookings from your user dashboard. You can cancel or reschedule your bookings as per the cancellation policy.
  5. Admin Dashboard:

    • If you are an admin, access the admin dashboard to manage users, bookings, and other administrative tasks.
  6. Receive Notifications:

    • Check your email for booking confirmations and updates. Ensure that you have provided a valid email address.
  7. Upload Documents:

    • Use the Cloudinary integration to upload and manage documents and images related to your trips.
  8. Unit Testing:

    • Run unit tests to ensure the reliability and quality of the codebase. Use the following command to run tests:
      npm run test

By following these steps, you can effectively use the "Are We There Yet?" application to plan and manage your trips.

Contribute

We welcome contributions to enhance the "Are We There Yet?" project. Here are some ways you can contribute:

  1. Report Bugs:

    • If you encounter any bugs or issues, please report them by creating an issue on the GitHub repository.
  2. Suggest Enhancements:

    • Have ideas to improve the project? Suggest new features or enhancements by opening an issue. Some potential enhancements include:
      • Real-time currency conversion to provide accurate pricing for users from different countries.
      • Integration with additional payment gateways to offer more payment options.
      • Improved search and filter functionality to help users find trips more easily.
      • Enhanced user profile management with more customization options.
      • Adding multi-language support to cater to users from different regions.
  3. Submit Pull Requests:

    • If you have implemented a bug fix or a new feature, submit a pull request. Please ensure your code follows the project's coding standards and includes appropriate tests.
  4. Improve Documentation:

    • Help us improve the documentation by adding more detailed instructions, code examples, or clarifying existing content.
  5. Write Tests:

    • Contribute by writing unit tests to increase the test coverage and ensure the reliability of the codebase.

How to Contribute

  1. Fork the Repository:

    • Fork the repository to your GitHub account.
  2. Clone the Repository:

    • Clone the forked repository to your local machine:
      git clone https://github.com/Advanced-computer-lab-2024/Are-we-there-yet
      cd Are-we-there-yet
  3. Create a Branch:

    • Create a new branch for your feature or bug fix:
      git checkout -b feature/your-feature-name
  4. Make Changes:

    • Make your changes to the codebase.
  5. Commit Changes:

    • Commit your changes with a descriptive commit message:
      git commit -m "feat: <your-feature-name>"
    • Please ensure your commit messages follow the conventional commit format. For example:
      • feat: Add new feature
      • fix: Correct typo in file
      • refactor: Refactor code for better performance
      • test: Add unit tests for component
  6. Push Changes:

    • Push your changes to your forked repository:
      git push origin feature/your-feature-name
  7. Submit a Pull Request:

    • Go to the original repository on GitHub and submit a pull request.

We appreciate your contributions and look forward to collaborating with you to improve the "Are We There Yet?" project.

Credits


Aid Used

Documentation

Video tutorials

Description Link
Google Maps How to load Maps JavaScript API in React
JWT Explanation What is JWT and Why Should You Use JWT
TypeScript TypeScript Crash Course

3rd Party Services

License

License

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages