Develop Full Stack Flight Booking System
Published: 2024-07-05 06:58:06

Creating a full-stack flight booking system with Next.js for the front end and NestJS for the back end is a substantial project. Here are some key features and functionalities that such a system could include:

### User Features

1. **User Registration and Authentication:**
   - Sign up, login, and logout.
   - Password recovery/reset.
   - Social media login (Google, Facebook, etc.).

2. **User Profile:**
   - View and edit profile information.
   - Upload profile picture.

3. **Flight Search and Booking:**
   - Search flights by destination, date, and other criteria.
   - View flight details (airline, departure/arrival time, duration, etc.).
   - Filter and sort search results.
   - Book selected flights.
   - View and manage bookings.
   - Receive booking confirmations via email.

4. **Payment Integration:**
   - Integration with payment gateways (PayPal, Stripe, etc.).
   - Secure payment processing.
   - View payment history.

5. **Notifications:**
   - Email and SMS notifications for booking confirmations, flight status updates, etc.

6. **Reviews and Ratings:**
   - Rate and review airlines and flights.
   - View reviews and ratings from other users.

### Admin Features

1. **Dashboard:**
   - Overview of bookings, users, flights, and revenue.

2. **Flight Management:**
   - Add, edit, and delete flights.
   - Manage flight schedules and availability.

3. **User Management:**
   - View and manage users.
   - Assign roles (e.g., admin, customer support).

4. **Booking Management:**
   - View and manage all bookings.
   - Cancel or modify bookings.

5. **Reporting and Analytics:**
   - Generate reports on bookings, revenue, user activity, etc.
   - Analyze data to make informed decisions.

### Functionalities

1. **API Integration:**
   - Integrate with third-party APIs for real-time flight data (e.g., Amadeus, Skyscanner).

2. **Security:**
   - Implement authentication and authorization (JWT, OAuth).
   - Secure data transmission (HTTPS).

3. **Performance Optimization:**
   - Optimize database queries.
   - Implement caching mechanisms.
   - Use CDN for static assets.

4. **Scalability:**
   - Design for horizontal scalability.
   - Use microservices architecture if needed.

5. **Testing:**
   - Unit and integration tests for back-end (NestJS).
   - End-to-end tests for the front end (Next.js).

6. **Documentation:**
   - API documentation (Swagger).
   - User manuals and help sections.

### Optional Advanced Features

1. **Multi-language Support:**
   - Provide interface and notifications in multiple languages.

2. **Loyalty Program:**
   - Implement a points or rewards system for frequent flyers.

3. **Customer Support:**
   - Live chat or chatbot integration.
   - Ticketing system for support requests.

4. **Mobile App:**
   - Develop a companion mobile app (using React Native or Flutter).

5. **Dynamic Pricing:**
   - Implement algorithms for dynamic pricing based on demand, season, etc.

By incorporating these features and functionalities, you'll have a comprehensive flight booking system that caters to both users and administrators effectively.

To implement user registration and authentication features in a NestJS backend, you'll need to set up a few key components, including modules, controllers, services, and guards for handling authentication and authorization. Below is a step-by-step guide with sample code for implementing these features:

### 1. Setting Up the Project

First, create a new NestJS project if you haven't already:

```bash
nest new flight-booking-backend
cd flight-booking-backend
```

### 2. Install Required Packages

You'll need some additional packages for authentication:

```bash
npm install @nestjs/jwt @nestjs/passport passport passport-jwt bcryptjs
```

### 3. Create Auth Module

Generate the authentication module and related components:

```bash
nest generate module auth
nest generate service auth
nest generate controller auth
```

### 4. User Entity

Create a user entity to represent users in the database. Assuming you are using TypeORM, it would look something like this:

```typescript
// src/user/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string;

  @Column({ nullable: true })
  googleId: string;

  @Column({ nullable: true })
  facebookId: string;
}
```

### 5. Auth Service

Implement the authentication logic in the AuthService:

```typescript
// src/auth/auth.service.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as bcrypt from 'bcryptjs';
import { User } from '../user/user.entity';
import { JwtPayload } from './jwt-payload.interface';
import { AuthCredentialsDto } from './dto/auth-credentials.dto';

@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
    private jwtService: JwtService,
  ) {}

  async signUp(authCredentialsDto: AuthCredentialsDto): Promise<void> {
    const { email, password } = authCredentialsDto;

    const salt = await bcrypt.genSalt();
    const hashedPassword = await bcrypt.hash(password, salt);

    const user = this.userRepository.create({ email, password: hashedPassword });
    await this.userRepository.save(user);
  }

  async validateUser(email: string, pass: string): Promise<any> {
    const user = await this.userRepository.findOne({ email });

    if (user && (await bcrypt.compare(pass, user.password))) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }

  async login(user: any) {
    const payload: JwtPayload = { email: user.email, sub: user.id };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}
```

### 6. Auth Controller

Create the controller to handle authentication requests:

```typescript
// src/auth/auth.controller.ts
import { Controller, Post, Body, UseGuards, Request } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthCredentialsDto } from './dto/auth-credentials.dto';
import { JwtAuthGuard } from './jwt-auth.guard';

@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}

  @Post('/signup')
  signUp(@Body() authCredentialsDto: AuthCredentialsDto): Promise<void> {
    return this.authService.signUp(authCredentialsDto);
  }

  @Post('/login')
  async login(@Body() authCredentialsDto: AuthCredentialsDto) {
    const user = await this.authService.validateUser(authCredentialsDto.email, authCredentialsDto.password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return this.authService.login(user);
  }
}
```

### 7. DTOs

Define the DTOs (Data Transfer Objects) for authentication:

```typescript
// src/auth/dto/auth-credentials.dto.ts
export class AuthCredentialsDto {
  email: string;
  password: string;
}
```

### 8. JWT Strategy

Configure the JWT strategy for handling authentication:

```typescript
// src/auth/jwt.strategy.ts
import { Strategy, ExtractJwt } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtPayload } from './jwt-payload.interface';
import { AuthService } from './auth.service';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    private authService: AuthService,
    private configService: ConfigService,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get<string>('JWT_SECRET'),
    });
  }

  async validate(payload: JwtPayload) {
    const user = await this.authService.validateUser(payload.email, null);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}
```

### 9. JWT Auth Guard

Create a guard to protect routes:

```typescript
// src/auth/jwt-auth.guard.ts
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  canActivate(context: ExecutionContext) {
    return super.canActivate(context);
  }
}
```

### 10. Auth Module Configuration

Configure the AuthModule to include necessary imports and providers:

```typescript
// src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from '../user/user.entity';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule,
    TypeOrmModule.forFeature([User]),
    PassportModule,
    JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        secret: configService.get<string>('JWT_SECRET'),
        signOptions: { expiresIn: '60m' },
      }),
    }),
  ],
  providers: [AuthService, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}
```

### 11. Environment Configuration

Finally, add the JWT secret to your environment variables:

```bash
# .env
JWT_SECRET=your_jwt_secret_key
```

And configure TypeORM to connect to your database:

```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { ConfigModule } from '@nestjs/config';
import { User } from './user/user.entity';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [User],
      synchronize: true,
    }),
    AuthModule,
  ],
})
export class AppModule {}
```

This setup should provide a robust foundation for user registration, login, and JWT-based authentication. You can expand on this by adding social login functionality, password reset, and other features as needed.

To implement user profile management, including viewing and editing profile information and uploading a profile picture, you'll need to extend the functionality of your existing NestJS application. Here's how to do it step by step:

### 1. Update User Entity

First, update the `User` entity to include fields for profile information and profile picture:

```typescript
// src/user/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string;

  @Column({ nullable: true })
  firstName: string;

  @Column({ nullable: true })
  lastName: string;

  @Column({ nullable: true })
  profilePicture: string;

  @Column({ nullable: true })
  googleId: string;

  @Column({ nullable: true })
  facebookId: string;
}
```

### 2. Create User Service

Implement methods in the UserService to handle profile operations:

```typescript
// src/user/user.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import { UpdateProfileDto } from './dto/update-profile.dto';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  async getProfile(userId: number): Promise<User> {
    const user = await this.userRepository.findOne(userId);
    if (!user) {
      throw new NotFoundException(`User with ID ${userId} not found`);
    }
    return user;
  }

  async updateProfile(userId: number, updateProfileDto: UpdateProfileDto): Promise<User> {
    await this.userRepository.update(userId, updateProfileDto);
    return this.getProfile(userId);
  }

  async updateProfilePicture(userId: number, profilePicture: string): Promise<User> {
    await this.userRepository.update(userId, { profilePicture });
    return this.getProfile(userId);
  }
}
```

### 3. Create DTOs

Define the DTOs for updating profile information:

```typescript
// src/user/dto/update-profile.dto.ts
export class UpdateProfileDto {
  firstName?: string;
  lastName?: string;
  profilePicture?: string;
}
```

### 4. Create User Controller

Implement the UserController to handle profile-related requests:

```typescript
// src/user/user.controller.ts
import { Controller, Get, Patch, Body, Param, UseGuards, UploadedFile, UseInterceptors } from '@nestjs/common';
import { UserService } from './user.service';
import { UpdateProfileDto } from './dto/update-profile.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';

@Controller('user')
@UseGuards(JwtAuthGuard)
export class UserController {
  constructor(private userService: UserService) {}

  @Get(':id')
  getProfile(@Param('id') id: string) {
    return this.userService.getProfile(+id);
  }

  @Patch(':id')
  updateProfile(@Param('id') id: string, @Body() updateProfileDto: UpdateProfileDto) {
    return this.userService.updateProfile(+id, updateProfileDto);
  }

  @Patch(':id/profile-picture')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads/profile-pictures',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const ext = extname(file.originalname);
          cb(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
        },
      }),
    }),
  )
  uploadProfilePicture(@Param('id') id: string, @UploadedFile() file: Express.Multer.File) {
    const profilePicture = `/uploads/profile-pictures/${file.filename}`;
    return this.userService.updateProfilePicture(+id, profilePicture);
  }
}
```

### 5. Update App Module

Ensure that the UserModule is imported in your AppModule and configure the `ServeStaticModule` for serving uploaded files:

```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { ConfigModule } from '@nestjs/config';
import { UserModule } from './user/user.module';
import { User } from './user/user.entity';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [User],
      synchronize: true,
    }),
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'uploads'),
      serveRoot: '/uploads',
    }),
    AuthModule,
    UserModule,
  ],
})
export class AppModule {}
```

### 6. Create User Module

Finally, create the UserModule to tie everything together:

```typescript
// src/user/user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UserService],
  controllers: [UserController],
  exports: [UserService],
})
export class UserModule {}
```

With this setup, you have created endpoints for viewing and editing user profile information and uploading a profile picture. The profile pictures are saved to the `./uploads/profile-pictures` directory and served statically via the `/uploads` URL path.

To implement flight search and booking functionality in the backend using NestJS, we'll need to define entities, services, controllers, and DTOs. Here's a step-by-step guide:

### 1. Define Flight and Booking Entities

First, define the `Flight` and `Booking` entities:

```typescript
// src/flight/flight.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Flight {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  airline: string;

  @Column()
  from: string;

  @Column()
  to: string;

  @Column()
  departureTime: Date;

  @Column()
  arrivalTime: Date;

  @Column('decimal')
  price: number;

  @Column()
  duration: string;
}
```

```typescript
// src/booking/booking.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Entity()
export class Booking {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(() => User, user => user.bookings)
  @JoinColumn({ name: 'userId' })
  user: User;

  @ManyToOne(() => Flight)
  @JoinColumn({ name: 'flightId' })
  flight: Flight;

  @Column()
  bookingDate: Date;

  @Column()
  status: string;
}
```

### 2. Create DTOs

Define DTOs for creating bookings and searching flights:

```typescript
// src/flight/dto/search-flight.dto.ts
export class SearchFlightDto {
  from: string;
  to: string;
  departureDate: Date;
  returnDate?: Date;
}

// src/booking/dto/create-booking.dto.ts
export class CreateBookingDto {
  flightId: number;
  userId: number;
}
```

### 3. Create Services

Implement services for flight search and booking operations:

```typescript
// src/flight/flight.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Flight } from './flight.entity';
import { SearchFlightDto } from './dto/search-flight.dto';

@Injectable()
export class FlightService {
  constructor(
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
  ) {}

  async searchFlights(searchFlightDto: SearchFlightDto): Promise<Flight[]> {
    const { from, to, departureDate, returnDate } = searchFlightDto;
    const query = this.flightRepository.createQueryBuilder('flight')
      .where('flight.from = :from', { from })
      .andWhere('flight.to = :to', { to })
      .andWhere('DATE(flight.departureTime) = :departureDate', { departureDate });

    if (returnDate) {
      query.andWhere('DATE(flight.arrivalTime) = :returnDate', { returnDate });
    }

    return query.getMany();
  }

  async getFlightById(id: number): Promise<Flight> {
    return this.flightRepository.findOne(id);
  }
}
```

```typescript
// src/booking/booking.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Booking } from './booking.entity';
import { CreateBookingDto } from './dto/create-booking.dto';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Injectable()
export class BookingService {
  constructor(
    @InjectRepository(Booking)
    private bookingRepository: Repository<Booking>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
  ) {}

  async createBooking(createBookingDto: CreateBookingDto): Promise<Booking> {
    const { flightId, userId } = createBookingDto;

    const user = await this.userRepository.findOne(userId);
    if (!user) {
      throw new NotFoundException(`User with ID ${userId} not found`);
    }

    const flight = await this.flightRepository.findOne(flightId);
    if (!flight) {
      throw new NotFoundException(`Flight with ID ${flightId} not found`);
    }

    const booking = this.bookingRepository.create({
      user,
      flight,
      bookingDate: new Date(),
      status: 'CONFIRMED',
    });

    await this.bookingRepository.save(booking);
    // Add email confirmation logic here

    return booking;
  }

  async getBookingsByUserId(userId: number): Promise<Booking[]> {
    return this.bookingRepository.find({
      where: { user: { id: userId } },
      relations: ['flight'],
    });
  }
}
```

### 4. Create Controllers

Implement controllers to handle flight search and booking requests:

```typescript
// src/flight/flight.controller.ts
import { Controller, Get, Query, Param } from '@nestjs/common';
import { FlightService } from './flight.service';
import { SearchFlightDto } from './dto/search-flight.dto';

@Controller('flights')
export class FlightController {
  constructor(private flightService: FlightService) {}

  @Get()
  searchFlights(@Query() searchFlightDto: SearchFlightDto) {
    return this.flightService.searchFlights(searchFlightDto);
  }

  @Get(':id')
  getFlightById(@Param('id') id: number) {
    return this.flightService.getFlightById(id);
  }
}
```

```typescript
// src/booking/booking.controller.ts
import { Controller, Post, Body, Get, Param, UseGuards } from '@nestjs/common';
import { BookingService } from './booking.service';
import { CreateBookingDto } from './dto/create-booking.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';

@Controller('bookings')
@UseGuards(JwtAuthGuard)
export class BookingController {
  constructor(private bookingService: BookingService) {}

  @Post()
  createBooking(@Body() createBookingDto: CreateBookingDto) {
    return this.bookingService.createBooking(createBookingDto);
  }

  @Get(':userId')
  getBookingsByUserId(@Param('userId') userId: number) {
    return this.bookingService.getBookingsByUserId(userId);
  }
}
```

### 5. Update App Module

Ensure that the `FlightModule` and `BookingModule` are imported in your AppModule:

```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { UserModule } from './user/user.module';
import { FlightModule } from './flight/flight.module';
import { BookingModule } from './booking/booking.module';
import { User } from './user/user.entity';
import { Flight } from './flight/flight.entity';
import { Booking } from './booking/booking.entity';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [User, Flight, Booking],
      synchronize: true,
    }),
    AuthModule,
    UserModule,
    FlightModule,
    BookingModule,
  ],
})
export class AppModule {}
```

### 6. Create Flight and Booking Modules

Create the Flight and Booking modules to tie everything together:

```typescript
// src/flight/flight.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { FlightService } from './flight.service';
import { FlightController } from './flight.controller';
import { Flight } from './flight.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Flight])],
  providers: [FlightService],
  controllers: [FlightController],
  exports: [FlightService],
})
export class FlightModule {}
```

```typescript
// src/booking/booking.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BookingService } from './booking.service';
import { BookingController } from './booking.controller';
import { Booking } from './booking.entity';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Booking, User, Flight])],
  providers: [BookingService],
  controllers: [BookingController],
  exports: [BookingService],
})
export class BookingModule {}
```

### 7. Email Confirmation (Optional)

For email confirmation, you can use a package like `nodemailer`. Here’s an example of how to integrate it:

```typescript
// src/booking/booking.service.ts (inside createBooking method)
import * as nodemailer from 'nodemailer';

async function sendBookingConfirmation(email: string, booking: Booking) {
  const transporter = nodemailer.createTransport({
    host: 'smtp.example.com',
    port: 587,
    secure: false,
    auth: {
      user: 'your_email@example.com',
      pass: 'your_email_password',
    },
  });

  const mailOptions = {
    from: 'your_email@example.com',
    to: email,
    subject:

 'Booking Confirmation',
    text: `Your booking is confirmed. Booking details: ${JSON.stringify(booking)}`,
  };

  await transporter.sendMail(mailOptions);
}

// Call this function after saving the booking
await this.bookingRepository.save(booking);
await sendBookingConfirmation(user.email, booking);
```

This setup should provide a comprehensive backend for flight search and booking functionalities. You can expand on this by adding more features like filtering, sorting, and better error handling as needed.

To integrate payment processing in a NestJS backend, you can use popular payment gateways like Stripe or PayPal. Below is an example of integrating Stripe for payment processing, secure payments, and viewing payment history.

### 1. Install Required Packages

First, install the Stripe package:

```bash
npm install @nestjs/common @nestjs/config stripe @nestjs/stripe
```

### 2. Configure Stripe

Add your Stripe API keys to your environment variables:

```bash
# .env
STRIPE_SECRET_KEY=your_stripe_secret_key
STRIPE_PUBLISHABLE_KEY=your_stripe_publishable_key
```

### 3. Create Payment Module

Generate the payment module and related components:

```bash
nest generate module payment
nest generate service payment
nest generate controller payment
```

### 4. Create Payment Entity

Define a `Payment` entity to store payment information:

```typescript
// src/payment/payment.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from '../user/user.entity';
import { Booking } from '../booking/booking.entity';

@Entity()
export class Payment {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  stripePaymentId: string;

  @Column()
  amount: number;

  @Column()
  currency: string;

  @Column()
  status: string;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'userId' })
  user: User;

  @ManyToOne(() => Booking)
  @JoinColumn({ name: 'bookingId' })
  booking: Booking;

  @Column()
  createdAt: Date;
}
```

### 5. Create Payment Service

Implement methods in the PaymentService to handle payment processing and viewing payment history:

```typescript
// src/payment/payment.service.ts
import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Payment } from './payment.entity';
import { User } from '../user/user.entity';
import { Booking } from '../booking/booking.entity';
import { ConfigService } from '@nestjs/config';
import Stripe from 'stripe';

@Injectable()
export class PaymentService {
  private stripe: Stripe;

  constructor(
    @InjectRepository(Payment)
    private paymentRepository: Repository<Payment>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Booking)
    private bookingRepository: Repository<Booking>,
    private configService: ConfigService,
  ) {
    this.stripe = new Stripe(this.configService.get<string>('STRIPE_SECRET_KEY'), {
      apiVersion: '2020-08-27',
    });
  }

  async processPayment(userId: number, bookingId: number, token: string): Promise<Payment> {
    const user = await this.userRepository.findOne(userId);
    if (!user) {
      throw new BadRequestException(`User with ID ${userId} not found`);
    }

    const booking = await this.bookingRepository.findOne(bookingId);
    if (!booking) {
      throw new BadRequestException(`Booking with ID ${bookingId} not found`);
    }

    const amount = 1000; // Amount in cents
    const currency = 'usd';

    const charge = await this.stripe.charges.create({
      amount,
      currency,
      source: token,
      description: `Payment for booking ${bookingId}`,
      receipt_email: user.email,
    });

    const payment = this.paymentRepository.create({
      stripePaymentId: charge.id,
      amount,
      currency,
      status: charge.status,
      user,
      booking,
      createdAt: new Date(),
    });

    return this.paymentRepository.save(payment);
  }

  async getPaymentHistory(userId: number): Promise<Payment[]> {
    return this.paymentRepository.find({
      where: { user: { id: userId } },
      relations: ['booking'],
      order: { createdAt: 'DESC' },
    });
  }
}
```

### 6. Create Payment Controller

Implement the PaymentController to handle payment-related requests:

```typescript
// src/payment/payment.controller.ts
import { Controller, Post, Body, Get, Param, UseGuards } from '@nestjs/common';
import { PaymentService } from './payment.service';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';

@Controller('payments')
@UseGuards(JwtAuthGuard)
export class PaymentController {
  constructor(private paymentService: PaymentService) {}

  @Post('process')
  async processPayment(@Body('userId') userId: number, @Body('bookingId') bookingId: number, @Body('token') token: string) {
    return this.paymentService.processPayment(userId, bookingId, token);
  }

  @Get('history/:userId')
  async getPaymentHistory(@Param('userId') userId: number) {
    return this.paymentService.getPaymentHistory(userId);
  }
}
```

### 7. Update App Module

Ensure that the `PaymentModule` is imported in your AppModule:

```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { UserModule } from './user/user.module';
import { FlightModule } from './flight/flight.module';
import { BookingModule } from './booking/booking.module';
import { PaymentModule } from './payment/payment.module';
import { User } from './user/user.entity';
import { Flight } from './flight/flight.entity';
import { Booking } from './booking/booking.entity';
import { Payment } from './payment/payment.entity';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [User, Flight, Booking, Payment],
      synchronize: true,
    }),
    AuthModule,
    UserModule,
    FlightModule,
    BookingModule,
    PaymentModule,
  ],
})
export class AppModule {}
```

### 8. Create Payment Module

Create the PaymentModule to tie everything together:

```typescript
// src/payment/payment.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PaymentService } from './payment.service';
import { PaymentController } from './payment.controller';
import { Payment } from './payment.entity';
import { User } from '../user/user.entity';
import { Booking } from '../booking/booking.entity';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [TypeOrmModule.forFeature([Payment, User, Booking]), ConfigModule],
  providers: [PaymentService],
  controllers: [PaymentController],
  exports: [PaymentService],
})
export class PaymentModule {}
```

### 9. Stripe Payment Processing Frontend Integration (Optional)

For the frontend, you would typically use Stripe.js to collect payment details and generate a payment token, which is then sent to your backend API to process the payment. Here’s a brief example of how you might collect the token:

```html
<!-- Add this script to your HTML -->
<script src="https://js.stripe.com/v3/"></script>
```

```javascript
// Example frontend code to get the Stripe token
const stripe = Stripe('your_stripe_publishable_key');

const handlePayment = async () => {
  const { token } = await stripe.createToken(cardElement); // cardElement is a reference to the card input field

  // Send token to your backend
  const response = await fetch('/payments/process', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      userId: 1,
      bookingId: 1,
      token: token.id,
    }),
  });

  const result = await response.json();
  console.log(result);
};
```

With this setup, you should have a fully functional payment processing system integrated with Stripe, along with secure payment handling and payment history viewing capabilities in your NestJS backend.

To implement email and SMS notifications for booking confirmations, flight status updates, and other notifications in a NestJS backend, we need to integrate with email and SMS service providers. We'll use Nodemailer for email notifications and Twilio for SMS notifications.

### 1. Install Required Packages

First, install the necessary packages:

```bash
npm install @nestjs/common @nestjs/config nodemailer twilio
```

### 2. Configure Environment Variables

Add your Twilio and email SMTP service credentials to your environment variables:

```bash
# .env
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_email@example.com
SMTP_PASS=your_email_password
TWILIO_ACCOUNT_SID=your_twilio_account_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token
TWILIO_PHONE_NUMBER=your_twilio_phone_number
```

### 3. Create Notification Module

Generate the notification module and related components:

```bash
nest generate module notification
nest generate service notification
nest generate controller notification
```

### 4. Create Notification Service

Implement methods in the NotificationService to handle email and SMS notifications:

```typescript
// src/notification/notification.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as nodemailer from 'nodemailer';
import { Twilio } from 'twilio';

@Injectable()
export class NotificationService {
  private transporter: nodemailer.Transporter;
  private twilioClient: Twilio;

  constructor(private configService: ConfigService) {
    this.transporter = nodemailer.createTransport({
      host: this.configService.get<string>('SMTP_HOST'),
      port: this.configService.get<number>('SMTP_PORT'),
      secure: false,
      auth: {
        user: this.configService.get<string>('SMTP_USER'),
        pass: this.configService.get<string>('SMTP_PASS'),
      },
    });

    this.twilioClient = new Twilio(
      this.configService.get<string>('TWILIO_ACCOUNT_SID'),
      this.configService.get<string>('TWILIO_AUTH_TOKEN'),
    );
  }

  async sendEmail(to: string, subject: string, text: string, html?: string) {
    const mailOptions = {
      from: this.configService.get<string>('SMTP_USER'),
      to,
      subject,
      text,
      html,
    };

    await this.transporter.sendMail(mailOptions);
  }

  async sendSms(to: string, body: string) {
    await this.twilioClient.messages.create({
      body,
      from: this.configService.get<string>('TWILIO_PHONE_NUMBER'),
      to,
    });
  }

  async sendBookingConfirmationEmail(userEmail: string, bookingDetails: any) {
    const subject = 'Booking Confirmation';
    const text = `Your booking is confirmed. Booking details: ${JSON.stringify(bookingDetails)}`;
    await this.sendEmail(userEmail, subject, text);
  }

  async sendBookingConfirmationSms(userPhone: string, bookingDetails: any) {
    const body = `Your booking is confirmed. Booking details: ${JSON.stringify(bookingDetails)}`;
    await this.sendSms(userPhone, body);
  }

  // Add more methods for other types of notifications as needed
}
```

### 5. Integrate Notification Service in Booking Service

Update the `BookingService` to send notifications upon booking confirmation:

```typescript
// src/booking/booking.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Booking } from './booking.entity';
import { CreateBookingDto } from './dto/create-booking.dto';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';
import { NotificationService } from '../notification/notification.service';

@Injectable()
export class BookingService {
  constructor(
    @InjectRepository(Booking)
    private bookingRepository: Repository<Booking>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
    private notificationService: NotificationService,
  ) {}

  async createBooking(createBookingDto: CreateBookingDto): Promise<Booking> {
    const { flightId, userId } = createBookingDto;

    const user = await this.userRepository.findOne(userId);
    if (!user) {
      throw new NotFoundException(`User with ID ${userId} not found`);
    }

    const flight = await this.flightRepository.findOne(flightId);
    if (!flight) {
      throw new NotFoundException(`Flight with ID ${flightId} not found`);
    }

    const booking = this.bookingRepository.create({
      user,
      flight,
      bookingDate: new Date(),
      status: 'CONFIRMED',
    });

    await this.bookingRepository.save(booking);

    // Send notifications
    await this.notificationService.sendBookingConfirmationEmail(user.email, booking);
    if (user.phone) {
      await this.notificationService.sendBookingConfirmationSms(user.phone, booking);
    }

    return booking;
  }

  async getBookingsByUserId(userId: number): Promise<Booking[]> {
    return this.bookingRepository.find({
      where: { user: { id: userId } },
      relations: ['flight'],
    });
  }
}
```

### 6. Update App Module

Ensure that the `NotificationModule` is imported in your AppModule:

```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { UserModule } from './user/user.module';
import { FlightModule } from './flight/flight.module';
import { BookingModule } from './booking/booking.module';
import { PaymentModule } from './payment/payment.module';
import { NotificationModule } from './notification/notification.module';
import { User } from './user/user.entity';
import { Flight } from './flight/flight.entity';
import { Booking } from './booking/booking.entity';
import { Payment } from './payment/payment.entity';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [User, Flight, Booking, Payment],
      synchronize: true,
    }),
    AuthModule,
    UserModule,
    FlightModule,
    BookingModule,
    PaymentModule,
    NotificationModule,
  ],
})
export class AppModule {}
```

### 7. Create Notification Module

Create the NotificationModule to tie everything together:

```typescript
// src/notification/notification.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { NotificationService } from './notification.service';

@Module({
  imports: [ConfigModule],
  providers: [NotificationService],
  exports: [NotificationService],
})
export class NotificationModule {}
```

This setup should provide a robust notification system that sends email and SMS notifications for booking confirmations and other updates. You can expand this by adding more notification types and integrating with additional email/SMS providers if needed.

To implement a reviews and ratings feature for airlines and flights in your NestJS backend, we need to create entities for reviews and ratings, services to handle the business logic, and controllers to expose the endpoints. Here’s how you can do it:

### 1. Create Review and Rating Entities

Define the `Review` and `Rating` entities. These will store the reviews and ratings given by users to flights.

```typescript
// src/review/review.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, CreateDateColumn } from 'typeorm';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Entity()
export class Review {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  content: string;

  @CreateDateColumn()
  createdAt: Date;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'userId' })
  user: User;

  @ManyToOne(() => Flight)
  @JoinColumn({ name: 'flightId' })
  flight: Flight;
}

// src/rating/rating.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, CreateDateColumn } from 'typeorm';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Entity()
export class Rating {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  score: number;

  @CreateDateColumn()
  createdAt: Date;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'userId' })
  user: User;

  @ManyToOne(() => Flight)
  @JoinColumn({ name: 'flightId' })
  flight: Flight;
}
```

### 2. Create Review and Rating Modules

Generate the review and rating modules and services:

```bash
nest generate module review
nest generate service review
nest generate controller review

nest generate module rating
nest generate service rating
nest generate controller rating
```

### 3. Create Review Service

Implement methods in the `ReviewService` to handle adding and viewing reviews:

```typescript
// src/review/review.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Review } from './review.entity';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';
import { CreateReviewDto } from './dto/create-review.dto';

@Injectable()
export class ReviewService {
  constructor(
    @InjectRepository(Review)
    private reviewRepository: Repository<Review>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
  ) {}

  async addReview(createReviewDto: CreateReviewDto): Promise<Review> {
    const { userId, flightId, content } = createReviewDto;

    const user = await this.userRepository.findOne(userId);
    if (!user) {
      throw new NotFoundException(`User with ID ${userId} not found`);
    }

    const flight = await this.flightRepository.findOne(flightId);
    if (!flight) {
      throw new NotFoundException(`Flight with ID ${flightId} not found`);
    }

    const review = this.reviewRepository.create({
      content,
      user,
      flight,
      createdAt: new Date(),
    });

    return this.reviewRepository.save(review);
  }

  async getReviewsByFlight(flightId: number): Promise<Review[]> {
    return this.reviewRepository.find({
      where: { flight: { id: flightId } },
      relations: ['user'],
      order: { createdAt: 'DESC' },
    });
  }
}
```

### 4. Create Rating Service

Implement methods in the `RatingService` to handle adding and viewing ratings:

```typescript
// src/rating/rating.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Rating } from './rating.entity';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';
import { CreateRatingDto } from './dto/create-rating.dto';

@Injectable()
export class RatingService {
  constructor(
    @InjectRepository(Rating)
    private ratingRepository: Repository<Rating>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
  ) {}

  async addRating(createRatingDto: CreateRatingDto): Promise<Rating> {
    const { userId, flightId, score } = createRatingDto;

    const user = await this.userRepository.findOne(userId);
    if (!user) {
      throw new NotFoundException(`User with ID ${userId} not found`);
    }

    const flight = await this.flightRepository.findOne(flightId);
    if (!flight) {
      throw new NotFoundException(`Flight with ID ${flightId} not found`);
    }

    const rating = this.ratingRepository.create({
      score,
      user,
      flight,
      createdAt: new Date(),
    });

    return this.ratingRepository.save(rating);
  }

  async getRatingsByFlight(flightId: number): Promise<Rating[]> {
    return this.ratingRepository.find({
      where: { flight: { id: flightId } },
      relations: ['user'],
      order: { createdAt: 'DESC' },
    });
  }
}
```

### 5. Create Review and Rating DTOs

Define DTOs for creating reviews and ratings:

```typescript
// src/review/dto/create-review.dto.ts
export class CreateReviewDto {
  userId: number;
  flightId: number;
  content: string;
}

// src/rating/dto/create-rating.dto.ts
export class CreateRatingDto {
  userId: number;
  flightId: number;
  score: number;
}
```

### 6. Create Review and Rating Controllers

Implement the `ReviewController` and `RatingController` to expose the endpoints:

```typescript
// src/review/review.controller.ts
import { Controller, Post, Body, Get, Param, UseGuards } from '@nestjs/common';
import { ReviewService } from './review.service';
import { CreateReviewDto } from './dto/create-review.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';

@Controller('reviews')
@UseGuards(JwtAuthGuard)
export class ReviewController {
  constructor(private reviewService: ReviewService) {}

  @Post()
  async addReview(@Body() createReviewDto: CreateReviewDto) {
    return this.reviewService.addReview(createReviewDto);
  }

  @Get('flight/:flightId')
  async getReviewsByFlight(@Param('flightId') flightId: number) {
    return this.reviewService.getReviewsByFlight(flightId);
  }
}

// src/rating/rating.controller.ts
import { Controller, Post, Body, Get, Param, UseGuards } from '@nestjs/common';
import { RatingService } from './rating.service';
import { CreateRatingDto } from './dto/create-rating.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';

@Controller('ratings')
@UseGuards(JwtAuthGuard)
export class RatingController {
  constructor(private ratingService: RatingService) {}

  @Post()
  async addRating(@Body() createRatingDto: CreateRatingDto) {
    return this.ratingService.addRating(createRatingDto);
  }

  @Get('flight/:flightId')
  async getRatingsByFlight(@Param('flightId') flightId: number) {
    return this.ratingService.getRatingsByFlight(flightId);
  }
}
```

### 7. Update App Module

Ensure that the `ReviewModule` and `RatingModule` are imported in your AppModule:

```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { UserModule } from './user/user.module';
import { FlightModule } from './flight/flight.module';
import { BookingModule } from './booking/booking.module';
import { PaymentModule } from './payment/payment.module';
import { NotificationModule } from './notification/notification.module';
import { ReviewModule } from './review/review.module';
import { RatingModule } from './rating/rating.module';
import { User } from './user/user.entity';
import { Flight } from './flight/flight.entity';
import { Booking } from './booking/booking.entity';
import { Payment } from './payment/payment.entity';
import { Review } from './review/review.entity';
import { Rating } from './rating/rating.entity';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DATABASE_HOST,
      port: parseInt(process.env.DATABASE_PORT, 10),
      username: process.env.DATABASE_USERNAME,
      password: process.env.DATABASE_PASSWORD,
      database: process.env.DATABASE_NAME,
      entities: [User, Flight, Booking, Payment, Review, Rating],
      synchronize: true,
    }),
    AuthModule,
    UserModule,
    FlightModule,
    BookingModule,
    PaymentModule,
    NotificationModule,
    ReviewModule,
    RatingModule,
  ],
})
export class AppModule {}
```

### 8. Create Review and Rating Modules

Create the ReviewModule and RatingModule to tie everything together:

```typescript
// src/review

/review.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ReviewService } from './review.service';
import { ReviewController } from './review.controller';
import { Review } from './review.entity';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Review, User, Flight])],
  providers: [ReviewService],
  controllers: [ReviewController],
})
export class ReviewModule {}

// src/rating/rating.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { RatingService } from './rating.service';
import { RatingController } from './rating.controller';
import { Rating } from './rating.entity';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Rating, User, Flight])],
  providers: [RatingService],
  controllers: [RatingController],
})
export class RatingModule {}
```

This setup should provide a comprehensive review and rating system for flights. You can expand this by adding more fields, validation, and additional features as needed.

To implement admin features such as a dashboard, flight management, and user management in your NestJS backend, you need to create the necessary entities, services, controllers, and guards for authorization. Here’s how you can do it:

### 1. Install Required Packages

Make sure you have the necessary packages installed:

```bash
npm install @nestjs/common @nestjs/config @nestjs/typeorm @nestjs/jwt bcryptjs
```

### 2. Create Admin Guard

Create a guard to protect routes that only admins should access:

```typescript
// src/auth/roles.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector, private jwtService: JwtService) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
      context.getHandler(),
      context.getClass(),
    ]);

    if (!requiredRoles) {
      return true;
    }

    const request = context.switchToHttp().getRequest();
    const token = request.headers.authorization?.split(' ')[1];

    if (!token) {
      return false;
    }

    const user = this.jwtService.decode(token);
    return requiredRoles.some((role) => user['roles']?.includes(role));
  }
}
```

Add a decorator to set roles on routes:

```typescript
// src/auth/roles.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
```

### 3. Create Dashboard Service

Implement methods in the `DashboardService` to fetch booking, user, flight, and revenue data:

```typescript
// src/admin/dashboard.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Booking } from '../booking/booking.entity';
import { User } from '../user/user.entity';
import { Flight } from '../flight/flight.entity';
import { Payment } from '../payment/payment.entity';

@Injectable()
export class DashboardService {
  constructor(
    @InjectRepository(Booking)
    private bookingRepository: Repository<Booking>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
    @InjectRepository(Payment)
    private paymentRepository: Repository<Payment>,
  ) {}

  async getOverview() {
    const totalBookings = await this.bookingRepository.count();
    const totalUsers = await this.userRepository.count();
    const totalFlights = await this.flightRepository.count();
    const totalRevenue = await this.paymentRepository
      .createQueryBuilder('payment')
      .select('SUM(payment.amount)', 'sum')
      .getRawOne();

    return {
      totalBookings,
      totalUsers,
      totalFlights,
      totalRevenue: totalRevenue.sum || 0,
    };
  }
}
```

### 4. Create Flight Management Service

Implement methods in the `FlightService` to handle adding, editing, and deleting flights:

```typescript
// src/flight/flight.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Flight } from './flight.entity';
import { CreateFlightDto } from './dto/create-flight.dto';
import { UpdateFlightDto } from './dto/update-flight.dto';

@Injectable()
export class FlightService {
  constructor(
    @InjectRepository(Flight)
    private flightRepository: Repository<Flight>,
  ) {}

  async createFlight(createFlightDto: CreateFlightDto): Promise<Flight> {
    const flight = this.flightRepository.create(createFlightDto);
    return this.flightRepository.save(flight);
  }

  async updateFlight(id: number, updateFlightDto: UpdateFlightDto): Promise<Flight> {
    const flight = await this.flightRepository.preload({
      id,
      ...updateFlightDto,
    });

    if (!flight) {
      throw new NotFoundException(`Flight with ID ${id} not found`);
    }

    return this.flightRepository.save(flight);
  }

  async deleteFlight(id: number): Promise<void> {
    const result = await this.flightRepository.delete(id);
    if (result.affected === 0) {
      throw new NotFoundException(`Flight with ID ${id} not found`);
    }
  }

  async getFlights(): Promise<Flight[]> {
    return this.flightRepository.find();
  }
}
```

### 5. Create User Management Service

Implement methods in the `UserService` to handle viewing and managing users, and assigning roles:

```typescript
// src/user/user.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  async getUsers(): Promise<User[]> {
    return this.userRepository.find();
  }

  async updateUser(id: number, updateUserDto: UpdateUserDto): Promise<User> {
    const user = await this.userRepository.preload({
      id,
      ...updateUserDto,
    });

    if (!user) {
      throw new NotFoundException(`User with ID ${id} not found`);
    }

    return this.userRepository.save(user);
  }

  async deleteUser(id: number): Promise<void> {
    const result = await this.userRepository.delete(id);
    if (result.affected === 0) {
      throw new NotFoundException(`User with ID ${id} not found`);
    }
  }
}
```

### 6. Create DTOs

Define DTOs for creating and updating flights and users:

```typescript
// src/flight/dto/create-flight.dto.ts
export class CreateFlightDto {
  airline: string;
  departure: string;
  arrival: string;
  departureTime: Date;
  arrivalTime: Date;
  price: number;
  availability: number;
}

// src/flight/dto/update-flight.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateFlightDto } from './create-flight.dto';

export class UpdateFlightDto extends PartialType(CreateFlightDto) {}

// src/user/dto/update-user.dto.ts
export class UpdateUserDto {
  username?: string;
  email?: string;
  roles?: string[];
}
```

### 7. Create Admin Controllers

Implement the `AdminController` to expose the endpoints for the dashboard, flight management, and user management:

```typescript
// src/admin/admin.controller.ts
import { Controller, Get, Post, Put, Delete, Body, Param, UseGuards } from '@nestjs/common';
import { DashboardService } from './dashboard.service';
import { FlightService } from '../flight/flight.service';
import { UserService } from '../user/user.service';
import { CreateFlightDto } from '../flight/dto/create-flight.dto';
import { UpdateFlightDto } from '../flight/dto/update-flight.dto';
import { UpdateUserDto } from '../user/dto/update-user.dto';
import { RolesGuard } from '../auth/roles.guard';
import { Roles } from '../auth/roles.decorator';

@Controller('admin')
@UseGuards(RolesGuard)
@Roles('admin')
export class AdminController {
  constructor(
    private dashboardService: DashboardService,
    private flightService: FlightService,
    private userService: UserService,
  ) {}

  @Get('dashboard')
  async getDashboard() {
    return this.dashboardService.getOverview();
  }

  @Get('flights')
  async getFlights() {
    return this.flightService.getFlights();
  }

  @Post('flights')
  async createFlight(@Body() createFlightDto: CreateFlightDto) {
    return this.flightService.createFlight(createFlightDto);
  }

  @Put('flights/:id')
  async updateFlight(@Param('id') id: number, @Body() updateFlightDto: UpdateFlightDto) {
    return this.flightService.updateFlight(id, updateFlightDto);
  }

  @Delete('flights/:id')
  async deleteFlight(@Param('id') id: number) {
    return this.flightService.deleteFlight(id);
  }

  @Get('users')
  async getUsers() {
    return this.userService.getUsers();
  }

  @Put('users/:id')
  async updateUser(@Param('id') id: number, @Body() updateUserDto: UpdateUserDto) {
    return this.userService.updateUser(id, updateUserDto);
  }

  @Delete('users/:id')
  async deleteUser(@Param('id') id: number) {
    return this.userService.deleteUser(id);
  }
}
```

### 8. Update App Module

Ensure that the `AdminModule`, `FlightModule`, and `UserModule` are imported in your AppModule:

Creating a backend for a full-stack flight booking system using NestJS involves several components. Below is a step-by-step guide with code snippets for each feature you listed. This guide assumes you have a basic understanding of NestJS and TypeScript.

1. **Initialize NestJS Project**
   
   First, create a new NestJS project:

   ```bash
   nest new flight-booking-backend
   cd flight-booking-backend
   ```

2. **Install Required Packages**

   Install the necessary packages:

   ```bash
   npm install @nestjs/typeorm typeorm mysql @nestjs/passport passport passport-local passport-jwt bcryptjs
   npm install @nestjs/jwt
   ```

3. **Set Up Database Connection**

   Configure TypeORM in your `app.module.ts`:

   ```typescript
   import { Module } from '@nestjs/common';
   import { TypeOrmModule } from '@nestjs/typeorm';
   import { User } from './users/user.entity';
   import { Flight } from './flights/flight.entity';
   import { Booking } from './bookings/booking.entity';

   @Module({
     imports: [
       TypeOrmModule.forRoot({
         type: 'mysql',
         host: 'localhost',
         port: 3306,
         username: 'root',
         password: 'password',
         database: 'flight_booking',
         entities: [User, Flight, Booking],
         synchronize: true,
       }),
       TypeOrmModule.forFeature([User, Flight, Booking]),
     ],
   })
   export class AppModule {}
   ```

4. **User Registration and Authentication**

   Create a user entity and authentication module.

   **user.entity.ts**

   ```typescript
   import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

   @Entity()
   export class User {
     @PrimaryGeneratedColumn()
     id: number;

     @Column()
     username: string;

     @Column()
     email: string;

     @Column()
     password: string;

     @Column({ default: 'user' })
     role: string;
   }
   ```

   **auth.module.ts**

   ```typescript
   import { Module } from '@nestjs/common';
   import { JwtModule } from '@nestjs/jwt';
   import { PassportModule } from '@nestjs/passport';
   import { AuthService } from './auth.service';
   import { JwtStrategy } from './jwt.strategy';
   import { UsersModule } from '../users/users.module';

   @Module({
     imports: [
       PassportModule,
       JwtModule.register({
         secret: 'secretKey',
         signOptions: { expiresIn: '1h' },
       }),
       UsersModule,
     ],
     providers: [AuthService, JwtStrategy],
     exports: [AuthService],
   })
   export class AuthModule {}
   ```

   **auth.service.ts**

   ```typescript
   import { Injectable } from '@nestjs/common';
   import { JwtService } from '@nestjs/jwt';
   import * as bcrypt from 'bcryptjs';
   import { UsersService } from '../users/users.service';

   @Injectable()
   export class AuthService {
     constructor(
       private readonly usersService: UsersService,
       private readonly jwtService: JwtService,
     ) {}

     async validateUser(username: string, password: string): Promise<any> {
       const user = await this.usersService.findOne(username);
       if (user && bcrypt.compareSync(password, user.password)) {
         const { password, ...result } = user;
         return result;
       }
       return null;
     }

     async login(user: any) {
       const payload = { username: user.username, sub: user.id, role: user.role };
       return {
         access_token: this.jwtService.sign(payload),
       };
     }

     async register(user: any) {
       const hashedPassword = bcrypt.hashSync(user.password, 8);
       return this.usersService.create({ ...user, password: hashedPassword });
     }
   }
   ```

   **jwt.strategy.ts**

   ```typescript
   import { Injectable } from '@nestjs/common';
   import { PassportStrategy } from '@nestjs/passport';
   import { ExtractJwt, Strategy } from 'passport-jwt';

   @Injectable()
   export class JwtStrategy extends PassportStrategy(Strategy) {
     constructor() {
       super({
         jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
         ignoreExpiration: false,
         secretOrKey: 'secretKey',
       });
     }

     async validate(payload: any) {
       return { userId: payload.sub, username: payload.username, role: payload.role };
     }
   }
   ```

5. **Flight Search and Booking**

   Create flight and booking entities and their respective modules and services.

   **flight.entity.ts**

   ```typescript
   import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

   @Entity()
   export class Flight {
     @PrimaryGeneratedColumn()
     id: number;

     @Column()
     airline: string;

     @Column()
     departureTime: Date;

     @Column()
     arrivalTime: Date;

     @Column()
     from: string;

     @Column()
     to: string;

     @Column()
     price: number;

     @Column()
     seatsAvailable: number;
   }
   ```

   **flight.module.ts**

   ```typescript
   import { Module } from '@nestjs/common';
   import { TypeOrmModule } from '@nestjs/typeorm';
   import { Flight } from './flight.entity';
   import { FlightService } from './flight.service';
   import { FlightController } from './flight.controller';

   @Module({
     imports: [TypeOrmModule.forFeature([Flight])],
     providers: [FlightService],
     controllers: [FlightController],
   })
   export class FlightModule {}
   ```

   **flight.service.ts**

   ```typescript
   import { Injectable } from '@nestjs/common';
   import { InjectRepository } from '@nestjs/typeorm';
   import { Repository } from 'typeorm';
   import { Flight } from './flight.entity';

   @Injectable()
   export class FlightService {
     constructor(
       @InjectRepository(Flight)
       private readonly flightRepository: Repository<Flight>,
     ) {}

     findAll(): Promise<Flight[]> {
       return this.flightRepository.find();
     }

     findOne(id: number): Promise<Flight> {
       return this.flightRepository.findOne(id);
     }

     create(flight: Flight): Promise<Flight> {
       return this.flightRepository.save(flight);
     }

     update(id: number, flight: Flight): Promise<any> {
       return this.flightRepository.update(id, flight);
     }

     delete(id: number): Promise<any> {
       return this.flightRepository.delete(id);
     }
   }
   ```

   **flight.controller.ts**

   ```typescript
   import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
   import { FlightService } from './flight.service';
   import { Flight } from './flight.entity';

   @Controller('flights')
   export class FlightController {
     constructor(private readonly flightService: FlightService) {}

     @Get()
     findAll(): Promise<Flight[]> {
       return this.flightService.findAll();
     }

     @Get(':id')
     findOne(@Param('id') id: number): Promise<Flight> {
       return this.flightService.findOne(id);
     }

     @Post()
     create(@Body() flight: Flight): Promise<Flight> {
       return this.flightService.create(flight);
     }

     @Put(':id')
     update(@Param('id') id: number, @Body() flight: Flight): Promise<any> {
       return this.flightService.update(id, flight);
     }

     @Delete(':id')
     delete(@Param('id') id: number): Promise<any> {
       return this.flightService.delete(id);
     }
   }
   ```

   **booking.entity.ts**

   ```typescript
   import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
   import { User } from '../users/user.entity';
   import { Flight } from '../flights/flight.entity';

   @Entity()
   export class Booking {
     @PrimaryGeneratedColumn()
     id: number;

     @ManyToOne(() => User)
     user: User;

     @ManyToOne(() => Flight)
     flight: Flight;

     @Column()
     status: string;

     @Column()
     bookingDate: Date;
   }
   ```

   **booking.module.ts**

   ```typescript
   import { Module } from '@nestjs/common';
   import { TypeOrmModule } from '@nestjs/typeorm';
   import { Booking } from './booking.entity';
   import { BookingService } from './booking.service';
   import { BookingController } from './booking.controller';

   @Module({
     imports: [TypeOrmModule.forFeature([Booking])],
     providers: [BookingService],
     controllers: [BookingController],
   })
   export class BookingModule {}
   ```

   **booking.service.ts**

   ```typescript
   import { Injectable } from '@nestjs/common';
   import { InjectRepository } from '@nestjs/typeorm';
   import { Repository } from 'typeorm';
   import { Booking } from './booking.entity';

   @Injectable()
   export class BookingService {
     constructor(
       @InjectRepository(Booking)
       private readonly bookingRepository: Repository<Booking>,
     ) {}

     findAll(): Promise<Booking[]> {
       return this.bookingRepository.find({ relations: ['user', 'flight'] });
     }

     findOne(id: number): Promise<Booking> {
       return this.bookingRepository.findOne(id, { relations: ['user', 'flight'] });
     }

     create(booking: Booking): Promise<Booking> {
       return this.bookingRepository.save(booking);
     }

     update

(id: number, booking: Booking): Promise<any> {
       return this.bookingRepository.update(id, booking);
     }

     delete(id: number): Promise<any> {
       return this.bookingRepository.delete(id);
     }
   }
   ```

   **booking.controller.ts**

   ```typescript
   import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
   import { BookingService } from './booking.service';
   import { Booking } from './booking.entity';

   @Controller('bookings')
   export class BookingController {
     constructor(private readonly bookingService: BookingService) {}

     @Get()
     findAll(): Promise<Booking[]> {
       return this.bookingService.findAll();
     }

     @Get(':id')
     findOne(@Param('id') id: number): Promise<Booking> {
       return this.bookingService.findOne(id);
     }

     @Post()
     create(@Body() booking: Booking): Promise<Booking> {
       return this.bookingService.create(booking);
     }

     @Put(':id')
     update(@Param('id') id: number, @Body() booking: Booking): Promise<any> {
       return this.bookingService.update(id, booking);
     }

     @Delete(':id')
     delete(@Param('id') id: number): Promise<any> {
       return this.bookingService.delete(id);
     }
   }
   ```

6. **Admin Features**

   For admin features, you can create specific controllers and services that will be accessible only to users with admin roles. You can use the `@Roles` decorator to restrict access.

   **roles.guard.ts**

   ```typescript
   import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
   import { Reflector } from '@nestjs/core';

   @Injectable()
   export class RolesGuard implements CanActivate {
     constructor(private reflector: Reflector) {}

     canActivate(context: ExecutionContext): boolean {
       const roles = this.reflector.get<string[]>('roles', context.getHandler());
       if (!roles) {
         return true;
       }
       const request = context.switchToHttp().getRequest();
       const user = request.user;
       return roles.some(role => role === user.role);
     }
   }
   ```

   **roles.decorator.ts**

   ```typescript
   import { SetMetadata } from '@nestjs/common';

   export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
   ```

   **flight.controller.ts (Admin)**

   ```typescript
   import { Controller, Get, Post, Put, Delete, Body, Param, UseGuards } from '@nestjs/common';
   import { FlightService } from './flight.service';
   import { Flight } from './flight.entity';
   import { Roles } from '../auth/roles.decorator';
   import { RolesGuard } from '../auth/roles.guard';
   import { AuthGuard } from '@nestjs/passport';

   @Controller('admin/flights')
   @UseGuards(AuthGuard('jwt'), RolesGuard)
   @Roles('admin')
   export class AdminFlightController {
     constructor(private readonly flightService: FlightService) {}

     @Get()
     findAll(): Promise<Flight[]> {
       return this.flightService.findAll();
     }

     @Get(':id')
     findOne(@Param('id') id: number): Promise<Flight> {
       return this.flightService.findOne(id);
     }

     @Post()
     create(@Body() flight: Flight): Promise<Flight> {
       return this.flightService.create(flight);
     }

     @Put(':id')
     update(@Param('id') id: number, @Body() flight: Flight): Promise<any> {
       return this.flightService.update(id, flight);
     }

     @Delete(':id')
     delete(@Param('id') id: number): Promise<any> {
       return this.flightService.delete(id);
     }
   }
   ```

This is a comprehensive setup for the backend of a flight booking system. You can expand and refine it according to your specific requirements, such as adding more sophisticated search and filter options, integrating third-party APIs for real-time flight data, or implementing payment gateways.

Creating the frontend for a user registration and authentication system using Next.js involves several components. Below is a step-by-step guide with code snippets for each feature you listed. This guide assumes you have a basic understanding of Next.js, React, and Apollo Client.

1. **Initialize Next.js Project**

   First, create a new Next.js project:

   ```bash
   npx create-next-app@latest flight-booking-frontend
   cd flight-booking-frontend
   ```

2. **Install Required Packages**

   Install the necessary packages:

   ```bash
   npm install @apollo/client graphql next-auth @mantine/core @mantine/hooks @mantine/dropzone
   ```

3. **Set Up Apollo Client**

   Create an `ApolloClient` instance in a file called `apollo-client.js`:

   **apollo-client.js**

   ```javascript
   import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
   import { setContext } from '@apollo/client/link/context';

   const httpLink = createHttpLink({
     uri: 'http://localhost:4000/graphql',
   });

   const authLink = setContext((_, { headers }) => {
     const token = localStorage.getItem('token');
     return {
       headers: {
         ...headers,
         authorization: token ? `Bearer ${token}` : '',
       },
     };
   });

   const client = new ApolloClient({
     link: authLink.concat(httpLink),
     cache: new InMemoryCache(),
   });

   export default client;
   ```

4. **User Registration and Authentication**

   Create the necessary GraphQL queries and mutations:

   **graphql/queries.js**

   ```javascript
   import { gql } from '@apollo/client';

   export const LOGIN_USER = gql`
     mutation LoginUser($username: String!, $password: String!) {
       login(username: $username, password: $password) {
         access_token
       }
     }
   `;

   export const REGISTER_USER = gql`
     mutation RegisterUser($username: String!, $email: String!, $password: String!) {
       register(username: $username, email: $email, password: $password) {
         id
         username
         email
       }
     }
   `;
   ```

   Create a login page:

   **pages/login.js**

   ```javascript
   import { useState } from 'react';
   import { useMutation } from '@apollo/client';
   import { LOGIN_USER } from '../graphql/queries';
   import { useRouter } from 'next/router';

   export default function Login() {
     const [username, setUsername] = useState('');
     const [password, setPassword] = useState('');
     const [login, { data, loading, error }] = useMutation(LOGIN_USER);
     const router = useRouter();

     const handleSubmit = async (e) => {
       e.preventDefault();
       try {
         const { data } = await login({ variables: { username, password } });
         localStorage.setItem('token', data.login.access_token);
         router.push('/');
       } catch (error) {
         console.error('Login failed', error);
       }
     };

     return (
       <div>
         <h1>Login</h1>
         <form onSubmit={handleSubmit}>
           <div>
             <label>Username</label>
             <input
               type="text"
               value={username}
               onChange={(e) => setUsername(e.target.value)}
             />
           </div>
           <div>
             <label>Password</label>
             <input
               type="password"
               value={password}
               onChange={(e) => setPassword(e.target.value)}
             />
           </div>
           <button type="submit" disabled={loading}>
             {loading ? 'Logging in...' : 'Login'}
           </button>
           {error && <p>Error: {error.message}</p>}
         </form>
       </div>
     );
   }
   ```

   Create a registration page:

   **pages/register.js**

   ```javascript
   import { useState } from 'react';
   import { useMutation } from '@apollo/client';
   import { REGISTER_USER } from '../graphql/queries';
   import { useRouter } from 'next/router';

   export default function Register() {
     const [username, setUsername] = useState('');
     const [email, setEmail] = useState('');
     const [password, setPassword] = useState('');
     const [register, { data, loading, error }] = useMutation(REGISTER_USER);
     const router = useRouter();

     const handleSubmit = async (e) => {
       e.preventDefault();
       try {
         await register({ variables: { username, email, password } });
         router.push('/login');
       } catch (error) {
         console.error('Registration failed', error);
       }
     };

     return (
       <div>
         <h1>Register</h1>
         <form onSubmit={handleSubmit}>
           <div>
             <label>Username</label>
             <input
               type="text"
               value={username}
               onChange={(e) => setUsername(e.target.value)}
             />
           </div>
           <div>
             <label>Email</label>
             <input
               type="email"
               value={email}
               onChange={(e) => setEmail(e.target.value)}
             />
           </div>
           <div>
             <label>Password</label>
             <input
               type="password"
               value={password}
               onChange={(e) => setPassword(e.target.value)}
             />
           </div>
           <button type="submit" disabled={loading}>
             {loading ? 'Registering...' : 'Register'}
           </button>
           {error && <p>Error: {error.message}</p>}
         </form>
       </div>
     );
   }
   ```

5. **User Profile**

   Create a profile page to view and edit profile information:

   **pages/profile.js**

   ```javascript
   import { useQuery, useMutation } from '@apollo/client';
   import { useState } from 'react';
   import { GET_USER_PROFILE, UPDATE_USER_PROFILE } from '../graphql/queries';
   import { useRouter } from 'next/router';

   export default function Profile() {
     const { data, loading, error } = useQuery(GET_USER_PROFILE);
     const [updateProfile] = useMutation(UPDATE_USER_PROFILE);
     const [username, setUsername] = useState('');
     const [email, setEmail] = useState('');
     const router = useRouter();

     if (loading) return <p>Loading...</p>;
     if (error) return <p>Error: {error.message}</p>;

     const handleSubmit = async (e) => {
       e.preventDefault();
       try {
         await updateProfile({ variables: { username, email } });
         router.push('/');
       } catch (error) {
         console.error('Update failed', error);
       }
     };

     return (
       <div>
         <h1>Profile</h1>
         <form onSubmit={handleSubmit}>
           <div>
             <label>Username</label>
             <input
               type="text"
               value={username}
               onChange={(e) => setUsername(e.target.value)}
             />
           </div>
           <div>
             <label>Email</label>
             <input
               type="email"
               value={email}
               onChange={(e) => setEmail(e.target.value)}
             />
           </div>
           <button type="submit">Update</button>
         </form>
       </div>
     );
   }
   ```

   **graphql/queries.js**

   ```javascript
   import { gql } from '@apollo/client';

   export const GET_USER_PROFILE = gql`
     query GetUserProfile {
       userProfile {
         id
         username
         email
       }
     }
   `;

   export const UPDATE_USER_PROFILE = gql`
     mutation UpdateUserProfile($username: String!, $email: String!) {
       updateUserProfile(username: $username, email: $email) {
         id
         username
         email
       }
     }
   `;
   ```

6. **Upload Profile Picture**

   Use Mantine for the file upload component. Install Mantine and set up the file upload:

   ```bash
   npm install @mantine/core @mantine/dropzone
   ```

   Create a file upload component:

   **components/ProfilePictureUpload.js**

   ```javascript
   import { useState } from 'react';
   import { Dropzone, IMAGE_MIME_TYPE } from '@mantine/dropzone';
   import { useMutation } from '@apollo/client';
   import { UPLOAD_PROFILE_PICTURE } from '../graphql/queries';

   export default function ProfilePictureUpload() {
     const [files, setFiles] = useState([]);
     const [uploadProfilePicture] = useMutation(UPLOAD_PROFILE_PICTURE);

     const handleDrop = async (acceptedFiles) => {
       setFiles(acceptedFiles);
       const formData = new FormData();
       formData.append('file', acceptedFiles[0]);

       try {
         await uploadProfilePicture({ variables: { file: acceptedFiles[0] } });
       } catch (error) {
         console.error('Upload failed', error);
       }
     };

     return (
       <Dropzone
         onDrop={handleDrop}
         accept={IMAGE_MIME_TYPE}
         multiple={false}
       >
         {(status) => (
           <div>
             <p>Drag images here or click to select files</p>
           </div>
         )}
       </Dropzone>
     );
   }
   ```

   **graphql/queries.js**

   ```javascript
   import

 { gql } from '@apollo/client';

   export const UPLOAD_PROFILE_PICTURE = gql`
     mutation UploadProfilePicture($file: Upload!) {
       uploadProfilePicture(file: $file) {
         url
       }
     }
   `;
   ```

7. **Integrate with Pages**

   Add the `ProfilePictureUpload` component to your profile page:

   **pages/profile.js**

   ```javascript
   import ProfilePictureUpload from '../components/ProfilePictureUpload';

   export default function Profile() {
     // ...existing code

     return (
       <div>
         <h1>Profile</h1>
         <ProfilePictureUpload />
         <form onSubmit={handleSubmit}>
           {/* ...existing code */}
         </form>
       </div>
     );
   }
   ```

8. **Social Media Login**

   Set up social media login using `next-auth`:

   ```bash
   npm install next-auth
   ```

   Configure `next-auth` in a file called `[...nextauth].js` in the `pages/api/auth` directory:

   **pages/api/auth/[...nextauth].js**

   ```javascript
   import NextAuth from 'next-auth';
   import Providers from 'next-auth/providers';

   export default NextAuth({
     providers: [
       Providers.Google({
         clientId: process.env.GOOGLE_CLIENT_ID,
         clientSecret: process.env.GOOGLE_CLIENT_SECRET,
       }),
       Providers.Facebook({
         clientId: process.env.FACEBOOK_CLIENT_ID,
         clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
       }),
     ],
     callbacks: {
       async jwt(token, user) {
         if (user) {
           token.id = user.id;
         }
         return token;
       },
       async session(session, token) {
         session.user.id = token.id;
         return session;
       },
     },
   });
   ```

   Create environment variables for your social media client IDs and secrets:

   **.env.local**

   ```plaintext
   GOOGLE_CLIENT_ID=your-google-client-id
   GOOGLE_CLIENT_SECRET=your-google-client-secret
   FACEBOOK_CLIENT_ID=your-facebook-client-id
   FACEBOOK_CLIENT_SECRET=your-facebook-client-secret
   ```

   Add social media login buttons to your login page:

   **pages/login.js**

   ```javascript
   import { signIn } from 'next-auth/client';

   export default function Login() {
     // ...existing code

     return (
       <div>
         <h1>Login</h1>
         <form onSubmit={handleSubmit}>
           {/* ...existing code */}
         </form>
         <button onClick={() => signIn('google')}>Login with Google</button>
         <button onClick={() => signIn('facebook')}>Login with Facebook</button>
       </div>
     );
   }
   ```

This should cover the main features for user registration, authentication, profile management, and social media login for your flight booking system's frontend using Next.js.

To implement flight search, booking, and management features on the frontend using Next.js, you need to set up several components and pages. Below is a step-by-step guide to help you build these features.

### 1. Initialize Next.js Project and Install Dependencies

If you haven't already, create a Next.js project and install the necessary dependencies:

```bash
npx create-next-app@latest flight-booking-frontend
cd flight-booking-frontend
npm install @apollo/client graphql react-hook-form date-fns
```

### 2. Set Up Apollo Client

Create an `ApolloClient` instance to interact with your GraphQL backend. 

**apollo-client.js**

```javascript
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

const httpLink = createHttpLink({
  uri: 'http://localhost:4000/graphql',
});

const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem('token');
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

export default client;
```

### 3. GraphQL Queries and Mutations

Define the necessary queries and mutations for flight search, booking, and user bookings.

**graphql/queries.js**

```javascript
import { gql } from '@apollo/client';

export const SEARCH_FLIGHTS = gql`
  query SearchFlights($from: String!, $to: String!, $departureDate: String!) {
    searchFlights(from: $from, to: $to, departureDate: $departureDate) {
      id
      airline
      from
      to
      departureTime
      arrivalTime
      duration
      price
    }
  }
`;

export const BOOK_FLIGHT = gql`
  mutation BookFlight($flightId: ID!, $userId: ID!) {
    bookFlight(flightId: $flightId, userId: $userId) {
      id
      flight {
        id
        airline
        from
        to
        departureTime
        arrivalTime
        duration
      }
      user {
        id
        username
      }
      bookingTime
    }
  }
`;

export const GET_USER_BOOKINGS = gql`
  query GetUserBookings($userId: ID!) {
    userBookings(userId: $userId) {
      id
      flight {
        id
        airline
        from
        to
        departureTime
        arrivalTime
        duration
      }
      bookingTime
    }
  }
`;
```

### 4. Flight Search Component

Create a flight search component to search for flights by destination, date, and other criteria.

**components/FlightSearch.js**

```javascript
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { useLazyQuery } from '@apollo/client';
import { SEARCH_FLIGHTS } from '../graphql/queries';
import { format } from 'date-fns';

export default function FlightSearch({ onFlightsFound }) {
  const { register, handleSubmit } = useForm();
  const [searchFlights, { data, loading, error }] = useLazyQuery(SEARCH_FLIGHTS);

  const onSubmit = async (formData) => {
    const { from, to, departureDate } = formData;
    await searchFlights({
      variables: {
        from,
        to,
        departureDate: format(new Date(departureDate), 'yyyy-MM-dd'),
      },
    });

    if (data) {
      onFlightsFound(data.searchFlights);
    }
  };

  return (
    <div>
      <h2>Search Flights</h2>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label>From:</label>
          <input type="text" {...register('from')} required />
        </div>
        <div>
          <label>To:</label>
          <input type="text" {...register('to')} required />
        </div>
        <div>
          <label>Departure Date:</label>
          <input type="date" {...register('departureDate')} required />
        </div>
        <button type="submit" disabled={loading}>
          {loading ? 'Searching...' : 'Search'}
        </button>
        {error && <p>Error: {error.message}</p>}
      </form>
    </div>
  );
}
```

### 5. Flight List Component

Create a component to display the list of searched flights and allow users to book a flight.

**components/FlightList.js**

```javascript
import { useMutation } from '@apollo/client';
import { BOOK_FLIGHT } from '../graphql/queries';

export default function FlightList({ flights, userId }) {
  const [bookFlight] = useMutation(BOOK_FLIGHT);

  const handleBook = async (flightId) => {
    try {
      await bookFlight({ variables: { flightId, userId } });
      alert('Flight booked successfully!');
    } catch (error) {
      console.error('Booking failed', error);
    }
  };

  return (
    <div>
      <h2>Available Flights</h2>
      {flights.map((flight) => (
        <div key={flight.id}>
          <p>Airline: {flight.airline}</p>
          <p>From: {flight.from}</p>
          <p>To: {flight.to}</p>
          <p>Departure: {flight.departureTime}</p>
          <p>Arrival: {flight.arrivalTime}</p>
          <p>Duration: {flight.duration}</p>
          <p>Price: ${flight.price}</p>
          <button onClick={() => handleBook(flight.id)}>Book Flight</button>
        </div>
      ))}
    </div>
  );
}
```

### 6. Bookings Page

Create a page to view and manage user bookings.

**pages/bookings.js**

```javascript
import { useQuery } from '@apollo/client';
import { GET_USER_BOOKINGS } from '../graphql/queries';
import { useEffect, useState } from 'react';

export default function Bookings({ userId }) {
  const { data, loading, error } = useQuery(GET_USER_BOOKINGS, {
    variables: { userId },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h2>Your Bookings</h2>
      {data.userBookings.map((booking) => (
        <div key={booking.id}>
          <p>Airline: {booking.flight.airline}</p>
          <p>From: {booking.flight.from}</p>
          <p>To: {booking.flight.to}</p>
          <p>Departure: {booking.flight.departureTime}</p>
          <p>Arrival: {booking.flight.arrivalTime}</p>
          <p>Duration: {booking.flight.duration}</p>
          <p>Booking Time: {booking.bookingTime}</p>
        </div>
      ))}
    </div>
  );
}
```

### 7. Home Page

Integrate the flight search and flight list components into the home page.

**pages/index.js**

```javascript
import { useState } from 'react';
import FlightSearch from '../components/FlightSearch';
import FlightList from '../components/FlightList';
import { useRouter } from 'next/router';

export default function Home() {
  const [flights, setFlights] = useState([]);
  const router = useRouter();
  const userId = 'current-user-id'; // Replace with the actual logged-in user ID

  const handleFlightsFound = (foundFlights) => {
    setFlights(foundFlights);
  };

  return (
    <div>
      <h1>Flight Booking System</h1>
      <FlightSearch onFlightsFound={handleFlightsFound} />
      {flights.length > 0 && <FlightList flights={flights} userId={userId} />}
      <button onClick={() => router.push('/bookings')}>View Bookings</button>
    </div>
  );
}
```

### 8. Setup Email Notifications (Optional)

To handle email notifications for booking confirmations, you would typically implement this feature on the backend. You can trigger an email notification when a booking is created using a service like SendGrid, Nodemailer, or any other email service.

### Final Steps

Ensure that your backend GraphQL API supports all the necessary queries and mutations for flights and bookings. This setup provides a robust foundation for your flight booking system's frontend. You can further enhance it with features like filtering, sorting, and more advanced error handling as needed.

Integrating payment gateways like Stripe into your Next.js application involves setting up payment forms, handling secure payment processing, and displaying payment history. Below is a step-by-step guide to implement these features on the frontend.

### 1. Initialize Project and Install Dependencies

If you haven't already, create a Next.js project and install the necessary dependencies:

```bash
npx create-next-app@latest flight-booking-frontend
cd flight-booking-frontend
npm install @stripe/stripe-js @stripe/react-stripe-js @apollo/client graphql react-hook-form date-fns
```

### 2. Set Up Apollo Client

If you haven't already, set up Apollo Client as shown in the previous sections.

### 3. Create Payment Form Component

Create a payment form component using Stripe's React components.

**components/CheckoutForm.js**

```javascript
import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js';
import { useState } from 'react';
import { useMutation } from '@apollo/client';
import { CREATE_PAYMENT_INTENT, SAVE_PAYMENT } from '../graphql/queries';

export default function CheckoutForm({ bookingId }) {
  const stripe = useStripe();
  const elements = useElements();
  const [createPaymentIntent] = useMutation(CREATE_PAYMENT_INTENT);
  const [savePayment] = useMutation(SAVE_PAYMENT);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const handleSubmit = async (event) => {
    event.preventDefault();
    setLoading(true);

    try {
      const { data } = await createPaymentIntent({ variables: { bookingId } });
      const clientSecret = data.createPaymentIntent.clientSecret;

      const cardElement = elements.getElement(CardElement);
      const paymentResult = await stripe.confirmCardPayment(clientSecret, {
        payment_method: { card: cardElement },
      });

      if (paymentResult.error) {
        setError(`Payment failed: ${paymentResult.error.message}`);
      } else if (paymentResult.paymentIntent.status === 'succeeded') {
        await savePayment({ variables: { bookingId, paymentIntentId: paymentResult.paymentIntent.id } });
        alert('Payment successful!');
      }
    } catch (error) {
      setError(`Payment failed: ${error.message}`);
    }

    setLoading(false);
  };

  return (
    <form onSubmit={handleSubmit}>
      <CardElement />
      <button type="submit" disabled={!stripe || loading}>
        {loading ? 'Processing...' : 'Pay'}
      </button>
      {error && <div>{error}</div>}
    </form>
  );
}
```

### 4. GraphQL Queries and Mutations

Define the necessary queries and mutations for creating payment intents and saving payments.

**graphql/queries.js**

```javascript
import { gql } from '@apollo/client';

export const CREATE_PAYMENT_INTENT = gql`
  mutation CreatePaymentIntent($bookingId: ID!) {
    createPaymentIntent(bookingId: $bookingId) {
      clientSecret
    }
  }
`;

export const SAVE_PAYMENT = gql`
  mutation SavePayment($bookingId: ID!, $paymentIntentId: String!) {
    savePayment(bookingId: $bookingId, paymentIntentId: $paymentIntentId) {
      id
      booking {
        id
        flight {
          airline
          from
          to
        }
      }
      amount
      currency
      status
    }
  }
`;

export const GET_PAYMENT_HISTORY = gql`
  query GetPaymentHistory($userId: ID!) {
    paymentHistory(userId: $userId) {
      id
      amount
      currency
      status
      createdAt
    }
  }
`;
```

### 5. Payment Page

Create a page to handle payment processing.

**pages/payment.js**

```javascript
import { loadStripe } from '@stripe/stripe-js';
import { Elements } from '@stripe/react-stripe-js';
import CheckoutForm from '../components/CheckoutForm';
import { useRouter } from 'next/router';

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);

export default function Payment() {
  const router = useRouter();
  const { bookingId } = router.query;

  return (
    <div>
      <h1>Complete Your Payment</h1>
      <Elements stripe={stripePromise}>
        <CheckoutForm bookingId={bookingId} />
      </Elements>
    </div>
  );
}
```

### 6. View Payment History

Create a page to view the user's payment history.

**pages/payment-history.js**

```javascript
import { useQuery } from '@apollo/client';
import { GET_PAYMENT_HISTORY } from '../graphql/queries';
import { useRouter } from 'next/router';

export default function PaymentHistory({ userId }) {
  const { data, loading, error } = useQuery(GET_PAYMENT_HISTORY, { variables: { userId } });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h2>Payment History</h2>
      {data.paymentHistory.map((payment) => (
        <div key={payment.id}>
          <p>Amount: {payment.amount} {payment.currency}</p>
          <p>Status: {payment.status}</p>
          <p>Date: {new Date(payment.createdAt).toLocaleString()}</p>
        </div>
      ))}
    </div>
  );
}
```

### 7. Environment Variables

Ensure you have your Stripe publishable key set in your environment variables.

**.env.local**

```plaintext
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your-stripe-publishable-key
```

### 8. Backend Integration (Necessary for Full Implementation)

While this guide focuses on the frontend, note that you must implement the corresponding backend logic in your NestJS application to handle:

1. Creating payment intents using Stripe.
2. Saving payment information after successful payments.
3. Providing payment history data via GraphQL queries.

### Final Steps

1. Ensure your backend is properly set up to handle Stripe payments and is accessible to your frontend.
2. Test the entire flow from searching flights, booking, making payments, and viewing payment history.

This setup should provide a robust foundation for integrating payment gateways into your flight booking system's frontend using Next.js.

### Email and SMS Notifications

To handle notifications, we will integrate with services like SendGrid for emails and Twilio for SMS notifications. We'll create components and hooks to send these notifications when needed. The actual sending logic will typically be handled by your backend, but we can trigger these notifications from the frontend.

### Reviews and Ratings

We'll create components to rate and review airlines and flights, and display reviews and ratings from other users.

### Step-by-Step Implementation

### 1. Initialize Project and Install Dependencies

If you haven't already, create a Next.js project and install the necessary dependencies:

```bash
npx create-next-app@latest flight-booking-frontend
cd flight-booking-frontend
npm install @apollo/client graphql react-hook-form date-fns
```

### 2. Set Up Apollo Client

Set up Apollo Client as shown in the previous sections.

### 3. GraphQL Queries and Mutations

Define the necessary queries and mutations for sending notifications, creating reviews, and fetching reviews.

**graphql/queries.js**

```javascript
import { gql } from '@apollo/client';

export const SEND_NOTIFICATION = gql`
  mutation SendNotification($type: String!, $to: String!, $message: String!) {
    sendNotification(type: $type, to: $to, message: $message) {
      success
      message
    }
  }
`;

export const CREATE_REVIEW = gql`
  mutation CreateReview($flightId: ID!, $rating: Int!, $comment: String!) {
    createReview(flightId: $flightId, rating: $rating, comment: $comment) {
      id
      flightId
      rating
      comment
      user {
        id
        username
      }
    }
  }
`;

export const GET_REVIEWS = gql`
  query GetReviews($flightId: ID!) {
    reviews(flightId: $flightId) {
      id
      rating
      comment
      user {
        id
        username
      }
    }
  }
`;
```

### 4. Notification Hook

Create a hook to send notifications.

**hooks/useNotification.js**

```javascript
import { useMutation } from '@apollo/client';
import { SEND_NOTIFICATION } from '../graphql/queries';

export const useNotification = () => {
  const [sendNotification, { loading, error }] = useMutation(SEND_NOTIFICATION);

  const notify = async (type, to, message) => {
    try {
      const response = await sendNotification({ variables: { type, to, message } });
      return response.data.sendNotification;
    } catch (error) {
      console.error('Notification error:', error);
      throw new Error('Failed to send notification');
    }
  };

  return { notify, loading, error };
};
```

### 5. Notification Component

Create a component to send notifications.

**components/Notification.js**

```javascript
import { useForm } from 'react-hook-form';
import { useNotification } from '../hooks/useNotification';

export default function Notification() {
  const { register, handleSubmit } = useForm();
  const { notify, loading, error } = useNotification();

  const onSubmit = async (formData) => {
    const { type, to, message } = formData;
    try {
      await notify(type, to, message);
      alert('Notification sent successfully!');
    } catch (error) {
      alert('Failed to send notification');
    }
  };

  return (
    <div>
      <h2>Send Notification</h2>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label>Type (email/sms):</label>
          <input type="text" {...register('type')} required />
        </div>
        <div>
          <label>To:</label>
          <input type="text" {...register('to')} required />
        </div>
        <div>
          <label>Message:</label>
          <textarea {...register('message')} required />
        </div>
        <button type="submit" disabled={loading}>
          {loading ? 'Sending...' : 'Send'}
        </button>
        {error && <p>Error: {error.message}</p>}
      </form>
    </div>
  );
}
```

### 6. Review and Rating Components

Create components to handle reviews and ratings.

**components/ReviewForm.js**

```javascript
import { useForm } from 'react-hook-form';
import { useMutation } from '@apollo/client';
import { CREATE_REVIEW } from '../graphql/queries';

export default function ReviewForm({ flightId, onReviewSubmitted }) {
  const { register, handleSubmit } = useForm();
  const [createReview, { loading, error }] = useMutation(CREATE_REVIEW);

  const onSubmit = async (formData) => {
    const { rating, comment } = formData;
    try {
      const response = await createReview({ variables: { flightId, rating: parseInt(rating), comment } });
      onReviewSubmitted(response.data.createReview);
    } catch (error) {
      console.error('Review submission error:', error);
    }
  };

  return (
    <div>
      <h2>Submit a Review</h2>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label>Rating (1-5):</label>
          <input type="number" {...register('rating')} min="1" max="5" required />
        </div>
        <div>
          <label>Comment:</label>
          <textarea {...register('comment')} required />
        </div>
        <button type="submit" disabled={loading}>
          {loading ? 'Submitting...' : 'Submit'}
        </button>
        {error && <p>Error: {error.message}</p>}
      </form>
    </div>
  );
}
```

**components/Reviews.js**

```javascript
import { useQuery } from '@apollo/client';
import { GET_REVIEWS } from '../graphql/queries';

export default function Reviews({ flightId }) {
  const { data, loading, error } = useQuery(GET_REVIEWS, { variables: { flightId } });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h2>Reviews</h2>
      {data.reviews.length > 0 ? (
        data.reviews.map((review) => (
          <div key={review.id}>
            <p>Rating: {review.rating}</p>
            <p>Comment: {review.comment}</p>
            <p>User: {review.user.username}</p>
          </div>
        ))
      ) : (
        <p>No reviews yet.</p>
      )}
    </div>
  );
}
```

### 7. Integrate Components into Pages

**pages/flight/[id].js**

```javascript
import { useRouter } from 'next/router';
import { useState } from 'react';
import ReviewForm from '../../components/ReviewForm';
import Reviews from '../../components/Reviews';

export default function FlightDetails() {
  const router = useRouter();
  const { id } = router.query;
  const [reviews, setReviews] = useState([]);

  const handleReviewSubmitted = (newReview) => {
    setReviews((prevReviews) => [...prevReviews, newReview]);
  };

  return (
    <div>
      <h1>Flight Details</h1>
      <p>Flight ID: {id}</p>
      {/* Render flight details here */}
      <ReviewForm flightId={id} onReviewSubmitted={handleReviewSubmitted} />
      <Reviews flightId={id} reviews={reviews} />
    </div>
  );
}
```

**pages/send-notification.js**

```javascript
import Notification from '../components/Notification';

export default function SendNotificationPage() {
  return (
    <div>
      <h1>Send Notification</h1>
      <Notification />
    </div>
  );
}
```

### Final Steps

1. Ensure your backend is properly set up to handle notifications and reviews.
2. Test the entire flow for sending notifications, submitting reviews, and viewing reviews.
3. Enhance the UI/UX as needed and handle edge cases and error scenarios gracefully.

This setup provides a robust foundation for handling notifications and reviews/ratings in your flight booking system's frontend using Next.js.

To implement the admin features for your flight booking system, we'll create components for the dashboard, flight management (adding, editing, and deleting flights), and managing flight schedules and availability. We'll use Apollo Client for GraphQL queries and mutations to interact with the backend.

### 1. Initialize Project and Install Dependencies

If you haven't already, create a Next.js project and install the necessary dependencies:

```bash
npx create-next-app@latest flight-booking-frontend
cd flight-booking-frontend
npm install @apollo/client graphql react-hook-form
```

### 2. Set Up Apollo Client

Set up Apollo Client as shown in the previous sections.

### 3. GraphQL Queries and Mutations

Define the necessary queries and mutations for managing flights and getting the dashboard overview.

**graphql/queries.js**

```javascript
import { gql } from '@apollo/client';

export const GET_DASHBOARD_OVERVIEW = gql`
  query GetDashboardOverview {
    dashboardOverview {
      bookingsCount
      usersCount
      flightsCount
      revenue
    }
  }
`;

export const GET_FLIGHTS = gql`
  query GetFlights {
    flights {
      id
      airline
      from
      to
      departureTime
      arrivalTime
      availableSeats
    }
  }
`;

export const CREATE_FLIGHT = gql`
  mutation CreateFlight($input: FlightInput!) {
    createFlight(input: $input) {
      id
      airline
      from
      to
      departureTime
      arrivalTime
      availableSeats
    }
  }
`;

export const UPDATE_FLIGHT = gql`
  mutation UpdateFlight($id: ID!, $input: FlightInput!) {
    updateFlight(id: $id, input: $input) {
      id
      airline
      from
      to
      departureTime
      arrivalTime
      availableSeats
    }
  }
`;

export const DELETE_FLIGHT = gql`
  mutation DeleteFlight($id: ID!) {
    deleteFlight(id: $id) {
      success
    }
  }
`;
```

### 4. Dashboard Component

Create a component to display the dashboard overview.

**components/Dashboard.js**

```javascript
import { useQuery } from '@apollo/client';
import { GET_DASHBOARD_OVERVIEW } from '../graphql/queries';

export default function Dashboard() {
  const { data, loading, error } = useQuery(GET_DASHBOARD_OVERVIEW);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const { bookingsCount, usersCount, flightsCount, revenue } = data.dashboardOverview;

  return (
    <div>
      <h1>Admin Dashboard</h1>
      <div>
        <h3>Overview</h3>
        <p>Bookings: {bookingsCount}</p>
        <p>Users: {usersCount}</p>
        <p>Flights: {flightsCount}</p>
        <p>Revenue: ${revenue}</p>
      </div>
    </div>
  );
}
```

### 5. Flight Management Components

Create components to manage flights: adding, editing, and deleting flights.

**components/FlightForm.js**

```javascript
import { useForm } from 'react-hook-form';
import { useMutation } from '@apollo/client';
import { CREATE_FLIGHT, UPDATE_FLIGHT } from '../graphql/queries';

export default function FlightForm({ flight, onCompleted }) {
  const { register, handleSubmit, reset } = useForm({
    defaultValues: flight || { airline: '', from: '', to: '', departureTime: '', arrivalTime: '', availableSeats: 0 },
  });
  const [createFlight] = useMutation(CREATE_FLIGHT, { onCompleted });
  const [updateFlight] = useMutation(UPDATE_FLIGHT, { onCompleted });

  const onSubmit = async (formData) => {
    if (flight) {
      await updateFlight({ variables: { id: flight.id, input: formData } });
    } else {
      await createFlight({ variables: { input: formData } });
    }
    reset();
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>Airline:</label>
        <input type="text" {...register('airline')} required />
      </div>
      <div>
        <label>From:</label>
        <input type="text" {...register('from')} required />
      </div>
      <div>
        <label>To:</label>
        <input type="text" {...register('to')} required />
      </div>
      <div>
        <label>Departure Time:</label>
        <input type="datetime-local" {...register('departureTime')} required />
      </div>
      <div>
        <label>Arrival Time:</label>
        <input type="datetime-local" {...register('arrivalTime')} required />
      </div>
      <div>
        <label>Available Seats:</label>
        <input type="number" {...register('availableSeats')} required />
      </div>
      <button type="submit">{flight ? 'Update' : 'Add'} Flight</button>
    </form>
  );
}
```

**components/FlightList.js**

```javascript
import { useQuery, useMutation } from '@apollo/client';
import { GET_FLIGHTS, DELETE_FLIGHT } from '../graphql/queries';

export default function FlightList({ onEdit }) {
  const { data, loading, error } = useQuery(GET_FLIGHTS);
  const [deleteFlight] = useMutation(DELETE_FLIGHT, {
    refetchQueries: [{ query: GET_FLIGHTS }],
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const handleDelete = async (id) => {
    await deleteFlight({ variables: { id } });
  };

  return (
    <div>
      <h2>Flights</h2>
      <ul>
        {data.flights.map((flight) => (
          <li key={flight.id}>
            <div>
              <p>Airline: {flight.airline}</p>
              <p>From: {flight.from}</p>
              <p>To: {flight.to}</p>
              <p>Departure Time: {new Date(flight.departureTime).toLocaleString()}</p>
              <p>Arrival Time: {new Date(flight.arrivalTime).toLocaleString()}</p>
              <p>Available Seats: {flight.availableSeats}</p>
              <button onClick={() => onEdit(flight)}>Edit</button>
              <button onClick={() => handleDelete(flight.id)}>Delete</button>
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### 6. Integrate Components into Pages

**pages/admin/dashboard.js**

```javascript
import Dashboard from '../../components/Dashboard';

export default function AdminDashboardPage() {
  return (
    <div>
      <Dashboard />
    </div>
  );
}
```

**pages/admin/flights.js**

```javascript
import { useState } from 'react';
import FlightForm from '../../components/FlightForm';
import FlightList from '../../components/FlightList';

export default function AdminFlightsPage() {
  const [selectedFlight, setSelectedFlight] = useState(null);

  const handleEdit = (flight) => {
    setSelectedFlight(flight);
  };

  const handleFormCompleted = () => {
    setSelectedFlight(null);
  };

  return (
    <div>
      <h1>Manage Flights</h1>
      <FlightForm flight={selectedFlight} onCompleted={handleFormCompleted} />
      <FlightList onEdit={handleEdit} />
    </div>
  );
}
```

### Final Steps

1. Ensure your backend is properly set up to handle flight management and provide dashboard data.
2. Test the entire flow for adding, editing, deleting flights, and viewing the dashboard.
3. Enhance the UI/UX as needed and handle edge cases and error scenarios gracefully.

This setup provides a robust foundation for managing flights and viewing dashboard data in your flight booking system's frontend using Next.js.

To implement the user management, booking management, and reporting and analytics features for your flight booking system, we'll create components for each feature and integrate them into your Next.js application. We'll use Apollo Client for GraphQL queries and mutations to interact with the backend.

### 1. Initialize Project and Install Dependencies

If you haven't already, create a Next.js project and install the necessary dependencies:

```bash
npx create-next-app@latest flight-booking-frontend
cd flight-booking-frontend
npm install @apollo/client graphql react-hook-form
```

### 2. Set Up Apollo Client

Set up Apollo Client as shown in the previous sections.

### 3. GraphQL Queries and Mutations

Define the necessary queries and mutations for managing users, bookings, and generating reports.

**graphql/queries.js**

```javascript
import { gql } from '@apollo/client';

export const GET_USERS = gql`
  query GetUsers {
    users {
      id
      username
      email
      role
    }
  }
`;

export const UPDATE_USER_ROLE = gql`
  mutation UpdateUserRole($id: ID!, $role: String!) {
    updateUserRole(id: $id, role: $role) {
      id
      username
      email
      role
    }
  }
`;

export const GET_BOOKINGS = gql`
  query GetBookings {
    bookings {
      id
      flight {
        id
        airline
        from
        to
      }
      user {
        id
        username
      }
      status
      createdAt
    }
  }
`;

export const UPDATE_BOOKING_STATUS = gql`
  mutation UpdateBookingStatus($id: ID!, $status: String!) {
    updateBookingStatus(id: $id, status: $status) {
      id
      status
    }
  }
`;

export const GET_REPORTS = gql`
  query GetReports {
    reports {
      bookingsCount
      revenue
      userActivity
    }
  }
`;
```

### 4. User Management Components

Create components to view and manage users and assign roles.

**components/UserList.js**

```javascript
import { useQuery, useMutation } from '@apollo/client';
import { GET_USERS, UPDATE_USER_ROLE } from '../graphql/queries';
import { useForm } from 'react-hook-form';

export default function UserList() {
  const { data, loading, error } = useQuery(GET_USERS);
  const [updateUserRole] = useMutation(UPDATE_USER_ROLE, {
    refetchQueries: [{ query: GET_USERS }],
  });
  const { register, handleSubmit } = useForm();

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const onSubmit = async (formData) => {
    await updateUserRole({ variables: { id: formData.id, role: formData.role } });
  };

  return (
    <div>
      <h2>User Management</h2>
      <ul>
        {data.users.map((user) => (
          <li key={user.id}>
            <p>Username: {user.username}</p>
            <p>Email: {user.email}</p>
            <p>Role: {user.role}</p>
            <form onSubmit={handleSubmit(onSubmit)}>
              <input type="hidden" value={user.id} {...register('id')} />
              <select {...register('role')}>
                <option value="admin">Admin</option>
                <option value="customer_support">Customer Support</option>
                <option value="user">User</option>
              </select>
              <button type="submit">Update Role</button>
            </form>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### 5. Booking Management Components

Create components to view and manage bookings.

**components/BookingList.js**

```javascript
import { useQuery, useMutation } from '@apollo/client';
import { GET_BOOKINGS, UPDATE_BOOKING_STATUS } from '../graphql/queries';
import { useForm } from 'react-hook-form';

export default function BookingList() {
  const { data, loading, error } = useQuery(GET_BOOKINGS);
  const [updateBookingStatus] = useMutation(UPDATE_BOOKING_STATUS, {
    refetchQueries: [{ query: GET_BOOKINGS }],
  });
  const { register, handleSubmit } = useForm();

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const onSubmit = async (formData) => {
    await updateBookingStatus({ variables: { id: formData.id, status: formData.status } });
  };

  return (
    <div>
      <h2>Booking Management</h2>
      <ul>
        {data.bookings.map((booking) => (
          <li key={booking.id}>
            <p>Flight: {booking.flight.airline} from {booking.flight.from} to {booking.flight.to}</p>
            <p>User: {booking.user.username}</p>
            <p>Status: {booking.status}</p>
            <form onSubmit={handleSubmit(onSubmit)}>
              <input type="hidden" value={booking.id} {...register('id')} />
              <select {...register('status')}>
                <option value="confirmed">Confirmed</option>
                <option value="cancelled">Cancelled</option>
              </select>
              <button type="submit">Update Status</button>
            </form>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### 6. Reporting and Analytics Components

Create components to generate reports and display analytics.

**components/Reports.js**

```javascript
import { useQuery } from '@apollo/client';
import { GET_REPORTS } from '../graphql/queries';

export default function Reports() {
  const { data, loading, error } = useQuery(GET_REPORTS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const { bookingsCount, revenue, userActivity } = data.reports;

  return (
    <div>
      <h2>Reports and Analytics</h2>
      <div>
        <p>Bookings Count: {bookingsCount}</p>
        <p>Revenue: ${revenue}</p>
        <p>User Activity: {userActivity}</p>
      </div>
    </div>
  );
}
```

### 7. Integrate Components into Pages

**pages/admin/users.js**

```javascript
import UserList from '../../components/UserList';

export default function AdminUsersPage() {
  return (
    <div>
      <h1>Manage Users</h1>
      <UserList />
    </div>
  );
}
```

**pages/admin/bookings.js**

```javascript
import BookingList from '../../components/BookingList';

export default function AdminBookingsPage() {
  return (
    <div>
      <h1>Manage Bookings</h1>
      <BookingList />
    </div>
  );
}
```

**pages/admin/reports.js**

```javascript
import Reports from '../../components/Reports';

export default function AdminReportsPage() {
  return (
    <div>
      <h1>Reports and Analytics</h1>
      <Reports />
    </div>
  );
}
```

### Final Steps

1. Ensure your backend is properly set up to handle user management, booking management, and generating reports.
2. Test the entire flow for viewing and managing users, bookings, and generating reports.
3. Enhance the UI/UX as needed and handle edge cases and error scenarios gracefully.

This setup provides a robust foundation for managing users, bookings, and generating reports in your flight booking system's frontend using Next.js.

Disclaimer: This content is generated by AI.