Develop Full Stack Event Management System
Published: 2024-07-05 06:15:49

Creating a full-stack event management system with Next.js, NestJS, and Tailwind CSS involves several key features and functionalities. Here's an outline of the features, the architecture, and the documentation to guide you through the development process:

## Features and Functionalities

### 1. User Authentication
- **Sign Up**: Users can create an account.
- **Login**: Users can log in to their account.
- **Password Reset**: Users can reset their password.

### 2. User Roles
- **Admin**: Can manage events, users, and system settings.
- **Organizer**: Can create and manage their own events.
- **Attendee**: Can view and register for events.

### 3. Event Management
- **Create Event**: Organizers can create events with details like title, description, date, time, venue, and ticket information.
- **Edit Event**: Organizers can edit their events.
- **Delete Event**: Organizers can delete their events.
- **View Event**: Users can view event details.
- **Search Events**: Users can search for events by various criteria (e.g., date, location, type).

### 4. Ticket Management
- **Create Tickets**: Organizers can create different types of tickets for an event.
- **Purchase Tickets**: Attendees can purchase tickets.
- **View Tickets**: Attendees can view their purchased tickets.

### 5. Notification System
- **Email Notifications**: Users receive email notifications for important actions (e.g., event creation, ticket purchase).
- **In-App Notifications**: Real-time notifications within the app.

### 6. Payment Integration
- **Payment Gateway**: Integrate with a payment gateway for ticket purchases.

### 7. Dashboard
- **Admin Dashboard**: Overview of system metrics, user management, event management.
- **Organizer Dashboard**: Overview of their events, ticket sales, attendee list.
- **Attendee Dashboard**: Overview of registered events and purchased tickets.

### 8. Analytics
- **Event Analytics**: Insights into event performance (e.g., ticket sales, attendee demographics).
- **User Analytics**: Insights into user behavior and engagement.

## Architecture and Tech Stack

### Frontend
- **Next.js**: For server-side rendering and frontend development.
- **Tailwind CSS**: For styling the frontend components.
- **React**: Core library for building UI components.

### Backend
- **NestJS**: For building the server-side application with TypeScript.
- **PostgreSQL**: For the database.
- **Prisma**: ORM for database interactions.
- **GraphQL**: API for communication between frontend and backend.

### Deployment
- **Vercel**: For deploying the Next.js application.
- **Heroku**: For deploying the NestJS backend.
- **Docker**: For containerizing the applications.

## Documentation

### 1. Setting Up the Development Environment

#### Prerequisites
- Node.js
- npm or yarn
- PostgreSQL
- Docker

#### Frontend (Next.js + Tailwind CSS)
1. Initialize Next.js project:
   ```bash
   npx create-next-app@latest event-management-frontend
   cd event-management-frontend
   ```

2. Install Tailwind CSS:
   ```bash
   npm install -D tailwindcss postcss autoprefixer
   npx tailwindcss init -p
   ```

3. Configure `tailwind.config.js`:
   ```javascript
   module.exports = {
     content: [
       "./pages/**/*.{js,ts,jsx,tsx}",
       "./components/**/*.{js,ts,jsx,tsx}",
     ],
     theme: {
       extend: {},
     },
     plugins: [],
   }
   ```

4. Add Tailwind directives to `styles/globals.css`:
   ```css
   @tailwind base;
   @tailwind components;
   @tailwind utilities;
   ```

#### Backend (NestJS + Prisma)
1. Initialize NestJS project:
   ```bash
   npm i -g @nestjs/cli
   nest new event-management-backend
   cd event-management-backend
   ```

2. Install Prisma and PostgreSQL client:
   ```bash
   npm install @nestjs/graphql @nestjs/apollo graphql apollo-server-express
   npm install @prisma/client
   npm install -D prisma
   ```

3. Initialize Prisma:
   ```bash
   npx prisma init
   ```

4. Configure `prisma/schema.prisma` for PostgreSQL:
   ```prisma
   datasource db {
     provider = "postgresql"
     url      = env("DATABASE_URL")
   }

   generator client {
     provider = "prisma-client-js"
   }

   model User {
     id        Int      @id @default(autoincrement())
     email     String   @unique
     password  String
     role      String
     events    Event[]
     tickets   Ticket[]
   }

   model Event {
     id          Int      @id @default(autoincrement())
     title       String
     description String
     date        DateTime
     organizer   User     @relation(fields: [organizerId], references: [id])
     organizerId Int
     tickets     Ticket[]
   }

   model Ticket {
     id        Int      @id @default(autoincrement())
     type      String
     price     Float
     event     Event    @relation(fields: [eventId], references: [id])
     eventId   Int
     attendee  User     @relation(fields: [attendeeId], references: [id])
     attendeeId Int
   }
   ```

5. Run Prisma migrations:
   ```bash
   npx prisma migrate dev --name init
   ```

### 2. Building the Features

#### User Authentication
- Implement signup, login, and password reset in NestJS.
- Create corresponding frontend pages in Next.js.

#### Event Management
- Create APIs for creating, editing, deleting, and viewing events in NestJS.
- Develop frontend components and pages for event management in Next.js.

#### Ticket Management
- Develop APIs for ticket creation, purchase, and viewing in NestJS.
- Create frontend components and pages for ticket management in Next.js.

#### Notification System
- Implement email notifications using a service like SendGrid.
- Develop in-app notifications using WebSockets.

#### Payment Integration
- Integrate with a payment gateway like Stripe or PayPal in NestJS.
- Implement payment workflows in the frontend.

#### Dashboard
- Build admin, organizer, and attendee dashboards with necessary metrics and features.

#### Analytics
- Use a library like Chart.js to display analytics in the frontend.
- Implement backend logic for aggregating and providing analytics data.

## Deployment

### Frontend
1. Deploy the Next.js application on Vercel.
2. Connect your GitHub repository to Vercel for automatic deployments.

### Backend
1. Create a Dockerfile for the NestJS application.
2. Deploy the NestJS application on Heroku using Docker.

This documentation provides a comprehensive guide to developing a full-stack event management system. Feel free to ask for more detailed information or specific code examples for any part of the process.

Sure! Here’s how you can implement the frontend for user authentication (Sign Up, Login, Password Reset) using Next.js and Tailwind CSS.

### Project Structure
```
event-management-frontend
├── components
│   ├── Auth
│   │   ├── LoginForm.js
│   │   ├── SignupForm.js
│   │   ├── PasswordResetForm.js
├── pages
│   ├── auth
│   │   ├── login.js
│   │   ├── signup.js
│   │   ├── reset-password.js
│   ├── index.js
└── styles
    └── globals.css
```

### 1. Sign Up

#### `components/Auth/SignupForm.js`
```javascript
import { useState } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const SignupForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState('');
  const router = useRouter();

  const handleSignup = async (e) => {
    e.preventDefault();
    if (password !== confirmPassword) {
      setError('Passwords do not match');
      return;
    }

    try {
      await axios.post('/api/auth/signup', { email, password });
      router.push('/auth/login');
    } catch (err) {
      setError(err.response.data.message);
    }
  };

  return (
    <div className="max-w-md mx-auto mt-10">
      <h1 className="text-2xl font-bold mb-6">Sign Up</h1>
      <form onSubmit={handleSignup}>
        <div className="mb-4">
          <label className="block text-gray-700">Email</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Password</label>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Confirm Password</label>
          <input
            type="password"
            value={confirmPassword}
            onChange={(e) => setConfirmPassword(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        {error && <p className="text-red-500">{error}</p>}
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Sign Up
        </button>
      </form>
    </div>
  );
};

export default SignupForm;
```

#### `pages/auth/signup.js`
```javascript
import SignupForm from '../../components/Auth/SignupForm';

const SignupPage = () => {
  return (
    <div>
      <SignupForm />
    </div>
  );
};

export default SignupPage;
```

### 2. Login

#### `components/Auth/LoginForm.js`
```javascript
import { useState } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const LoginForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const router = useRouter();

  const handleLogin = async (e) => {
    e.preventDefault();

    try {
      await axios.post('/api/auth/login', { email, password });
      router.push('/');
    } catch (err) {
      setError(err.response.data.message);
    }
  };

  return (
    <div className="max-w-md mx-auto mt-10">
      <h1 className="text-2xl font-bold mb-6">Login</h1>
      <form onSubmit={handleLogin}>
        <div className="mb-4">
          <label className="block text-gray-700">Email</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Password</label>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        {error && <p className="text-red-500">{error}</p>}
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Login
        </button>
      </form>
    </div>
  );
};

export default LoginForm;
```

#### `pages/auth/login.js`
```javascript
import LoginForm from '../../components/Auth/LoginForm';

const LoginPage = () => {
  return (
    <div>
      <LoginForm />
    </div>
  );
};

export default LoginPage;
```

### 3. Password Reset

#### `components/Auth/PasswordResetForm.js`
```javascript
import { useState } from 'react';
import axios from 'axios';

const PasswordResetForm = () => {
  const [email, setEmail] = useState('');
  const [message, setMessage] = useState('');
  const [error, setError] = useState('');

  const handlePasswordReset = async (e) => {
    e.preventDefault();

    try {
      await axios.post('/api/auth/reset-password', { email });
      setMessage('A password reset link has been sent to your email');
    } catch (err) {
      setError(err.response.data.message);
    }
  };

  return (
    <div className="max-w-md mx-auto mt-10">
      <h1 className="text-2xl font-bold mb-6">Reset Password</h1>
      <form onSubmit={handlePasswordReset}>
        <div className="mb-4">
          <label className="block text-gray-700">Email</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        {message && <p className="text-green-500">{message}</p>}
        {error && <p className="text-red-500">{error}</p>}
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Reset Password
        </button>
      </form>
    </div>
  );
};

export default PasswordResetForm;
```

#### `pages/auth/reset-password.js`
```javascript
import PasswordResetForm from '../../components/Auth/PasswordResetForm';

const PasswordResetPage = () => {
  return (
    <div>
      <PasswordResetForm />
    </div>
  );
};

export default PasswordResetPage;
```

### Styles
Make sure you have Tailwind CSS properly configured in your `globals.css` as mentioned in the initial setup.

### API Endpoints
The above forms make POST requests to `/api/auth/signup`, `/api/auth/login`, and `/api/auth/reset-password`. You need to implement these endpoints in your backend (NestJS) to handle these requests.

This setup should give you a fully functioning frontend for user authentication in your event management system.

To implement user roles (Admin, Organizer, and Attendee) in the frontend using Next.js and Tailwind CSS, you'll need to create different components and pages for each role. Here's an example setup for each role's dashboard and basic functionality.

### Project Structure
```
event-management-frontend
├── components
│   ├── Admin
│   │   ├── AdminDashboard.js
│   │   ├── ManageEvents.js
│   │   ├── ManageUsers.js
│   ├── Organizer
│   │   ├── OrganizerDashboard.js
│   │   ├── CreateEvent.js
│   │   ├── ManageOwnEvents.js
│   ├── Attendee
│   │   ├── AttendeeDashboard.js
│   │   ├── ViewEvents.js
│   │   ├── RegisterEvent.js
├── pages
│   ├── admin
│   │   ├── index.js
│   │   ├── manage-events.js
│   │   ├── manage-users.js
│   ├── organizer
│   │   ├── index.js
│   │   ├── create-event.js
│   │   ├── manage-events.js
│   ├── attendee
│   │   ├── index.js
│   │   ├── view-events.js
│   │   ├── register-event.js
└── styles
    └── globals.css
```

### 1. Admin

#### `components/Admin/AdminDashboard.js`
```javascript
const AdminDashboard = () => {
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Admin Dashboard</h1>
      <div className="flex space-x-4">
        <a href="/admin/manage-events" className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">Manage Events</a>
        <a href="/admin/manage-users" className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">Manage Users</a>
      </div>
    </div>
  );
};

export default AdminDashboard;
```

#### `components/Admin/ManageEvents.js`
```javascript
const ManageEvents = () => {
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Manage Events</h1>
      {/* Add functionality to list and manage all events */}
    </div>
  );
};

export default ManageEvents;
```

#### `components/Admin/ManageUsers.js`
```javascript
const ManageUsers = () => {
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Manage Users</h1>
      {/* Add functionality to list and manage all users */}
    </div>
  );
};

export default ManageUsers;
```

#### `pages/admin/index.js`
```javascript
import AdminDashboard from '../../components/Admin/AdminDashboard';

const AdminPage = () => {
  return (
    <div>
      <AdminDashboard />
    </div>
  );
};

export default AdminPage;
```

#### `pages/admin/manage-events.js`
```javascript
import ManageEvents from '../../components/Admin/ManageEvents';

const ManageEventsPage = () => {
  return (
    <div>
      <ManageEvents />
    </div>
  );
};

export default ManageEventsPage;
```

#### `pages/admin/manage-users.js`
```javascript
import ManageUsers from '../../components/Admin/ManageUsers';

const ManageUsersPage = () => {
  return (
    <div>
      <ManageUsers />
    </div>
  );
};

export default ManageUsersPage;
```

### 2. Organizer

#### `components/Organizer/OrganizerDashboard.js`
```javascript
const OrganizerDashboard = () => {
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Organizer Dashboard</h1>
      <div className="flex space-x-4">
        <a href="/organizer/create-event" className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">Create Event</a>
        <a href="/organizer/manage-events" className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">Manage Events</a>
      </div>
    </div>
  );
};

export default OrganizerDashboard;
```

#### `components/Organizer/CreateEvent.js`
```javascript
import { useState } from 'react';
import axios from 'axios';

const CreateEvent = () => {
  const [title, setTitle] = useState('');
  const [description, setDescription] = useState('');
  const [date, setDate] = useState('');
  const [time, setTime] = useState('');
  const [venue, setVenue] = useState('');

  const handleCreateEvent = async (e) => {
    e.preventDefault();

    try {
      await axios.post('/api/events', { title, description, date, time, venue });
      alert('Event created successfully');
    } catch (err) {
      console.error(err);
      alert('Error creating event');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Create Event</h1>
      <form onSubmit={handleCreateEvent}>
        <div className="mb-4">
          <label className="block text-gray-700">Title</label>
          <input
            type="text"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Description</label>
          <textarea
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          ></textarea>
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Date</label>
          <input
            type="date"
            value={date}
            onChange={(e) => setDate(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Time</label>
          <input
            type="time"
            value={time}
            onChange={(e) => setTime(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Venue</label>
          <input
            type="text"
            value={venue}
            onChange={(e) => setVenue(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Create Event
        </button>
      </form>
    </div>
  );
};

export default CreateEvent;
```

#### `components/Organizer/ManageOwnEvents.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const ManageOwnEvents = () => {
  const [events, setEvents] = useState([]);

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/organizer/events');
      setEvents(response.data);
    };

    fetchEvents();
  }, []);

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Manage Your Events</h1>
      <div>
        {events.map((event) => (
          <div key={event.id} className="mb-4 p-4 border rounded">
            <h2 className="text-2xl font-bold">{event.title}</h2>
            <p>{event.description}</p>
            <p>{new Date(event.date).toLocaleDateString()} {event.time}</p>
            <p>{event.venue}</p>
            {/* Add buttons for editing and deleting the event */}
          </div>
        ))}
      </div>
    </div>
  );
};

export default ManageOwnEvents;
```

#### `pages/organizer/index.js`
```javascript
import OrganizerDashboard from '../../components/Organizer/OrganizerDashboard';

const OrganizerPage = () => {
  return (
    <div>
      <OrganizerDashboard />
    </div>
  );
};

export default OrganizerPage;
```

#### `pages/organizer/create-event.js`
```javascript
import CreateEvent from '../../components/Organizer/CreateEvent';

const CreateEventPage = () => {
  return (
    <div>
      <CreateEvent />
    </div>
  );
};

export default CreateEventPage;


```

#### `pages/organizer/manage-events.js`
```javascript
import ManageOwnEvents from '../../components/Organizer/ManageOwnEvents';

const ManageOwnEventsPage = () => {
  return (
    <div>
      <ManageOwnEvents />
    </div>
  );
};

export default ManageOwnEventsPage;
```

### 3. Attendee

#### `components/Attendee/AttendeeDashboard.js`
```javascript
const AttendeeDashboard = () => {
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Attendee Dashboard</h1>
      <div className="flex space-x-4">
        <a href="/attendee/view-events" className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">View Events</a>
        <a href="/attendee/register-event" className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700">Register for Event</a>
      </div>
    </div>
  );
};

export default AttendeeDashboard;
```

#### `components/Attendee/ViewEvents.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const ViewEvents = () => {
  const [events, setEvents] = useState([]);

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/events');
      setEvents(response.data);
    };

    fetchEvents();
  }, []);

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">View Events</h1>
      <div>
        {events.map((event) => (
          <div key={event.id} className="mb-4 p-4 border rounded">
            <h2 className="text-2xl font-bold">{event.title}</h2>
            <p>{event.description}</p>
            <p>{new Date(event.date).toLocaleDateString()} {event.time}</p>
            <p>{event.venue}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default ViewEvents;
```

#### `components/Attendee/RegisterEvent.js`
```javascript
import { useState } from 'react';
import axios from 'axios';

const RegisterEvent = () => {
  const [eventId, setEventId] = useState('');

  const handleRegister = async (e) => {
    e.preventDefault();

    try {
      await axios.post(`/api/events/${eventId}/register`);
      alert('Successfully registered for the event');
    } catch (err) {
      console.error(err);
      alert('Error registering for the event');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Register for Event</h1>
      <form onSubmit={handleRegister}>
        <div className="mb-4">
          <label className="block text-gray-700">Event ID</label>
          <input
            type="text"
            value={eventId}
            onChange={(e) => setEventId(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Register
        </button>
      </form>
    </div>
  );
};

export default RegisterEvent;
```

#### `pages/attendee/index.js`
```javascript
import AttendeeDashboard from '../../components/Attendee/AttendeeDashboard';

const AttendeePage = () => {
  return (
    <div>
      <AttendeeDashboard />
    </div>
  );
};

export default AttendeePage;
```

#### `pages/attendee/view-events.js`
```javascript
import ViewEvents from '../../components/Attendee/ViewEvents';

const ViewEventsPage = () => {
  return (
    <div>
      <ViewEvents />
    </div>
  );
};

export default ViewEventsPage;
```

#### `pages/attendee/register-event.js`
```javascript
import RegisterEvent from '../../components/Attendee/RegisterEvent';

const RegisterEventPage = () => {
  return (
    <div>
      <RegisterEvent />
    </div>
  );
};

export default RegisterEventPage;
```

### Navigation and Authorization
You should also implement navigation and role-based authorization checks to ensure users only access the pages they are allowed to. This can be achieved using a combination of custom hooks, context providers, and middleware.

### Styles
Make sure Tailwind CSS is properly configured in your `globals.css`.

With these components and pages, you can build a user role-based frontend for your event management system. The functionality for each role can be expanded as needed.

To implement event management features in the frontend using Next.js and Tailwind CSS, you'll need components and pages for creating, editing, deleting, viewing, and searching events. Below is an example setup for these functionalities.

### Project Structure
```
event-management-frontend
├── components
│   ├── Organizer
│   │   ├── CreateEvent.js
│   │   ├── EditEvent.js
│   │   ├── DeleteEvent.js
│   │   ├── ManageOwnEvents.js
│   ├── Event
│   │   ├── EventDetails.js
│   │   ├── SearchEvents.js
├── pages
│   ├── organizer
│   │   ├── create-event.js
│   │   ├── edit-event.js
│   │   ├── manage-events.js
│   ├── events
│   │   ├── [id].js
│   │   ├── search.js
└── styles
    └── globals.css
```

### 1. Create Event

#### `components/Organizer/CreateEvent.js`
```javascript
import { useState } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const CreateEvent = () => {
  const [title, setTitle] = useState('');
  const [description, setDescription] = useState('');
  const [date, setDate] = useState('');
  const [time, setTime] = useState('');
  const [venue, setVenue] = useState('');
  const [ticketInfo, setTicketInfo] = useState('');

  const router = useRouter();

  const handleCreateEvent = async (e) => {
    e.preventDefault();

    try {
      await axios.post('/api/events', { title, description, date, time, venue, ticketInfo });
      router.push('/organizer/manage-events');
    } catch (err) {
      console.error(err);
      alert('Error creating event');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Create Event</h1>
      <form onSubmit={handleCreateEvent}>
        <div className="mb-4">
          <label className="block text-gray-700">Title</label>
          <input
            type="text"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Description</label>
          <textarea
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          ></textarea>
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Date</label>
          <input
            type="date"
            value={date}
            onChange={(e) => setDate(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Time</label>
          <input
            type="time"
            value={time}
            onChange={(e) => setTime(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Venue</label>
          <input
            type="text"
            value={venue}
            onChange={(e) => setVenue(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Ticket Information</label>
          <input
            type="text"
            value={ticketInfo}
            onChange={(e) => setTicketInfo(e.target.value)}
            className="w-full px-3 py-2 border rounded"
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Create Event
        </button>
      </form>
    </div>
  );
};

export default CreateEvent;
```

#### `pages/organizer/create-event.js`
```javascript
import CreateEvent from '../../components/Organizer/CreateEvent';

const CreateEventPage = () => {
  return (
    <div>
      <CreateEvent />
    </div>
  );
};

export default CreateEventPage;
```

### 2. Edit Event

#### `components/Organizer/EditEvent.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';
import { useRouter } from 'next/router';

const EditEvent = () => {
  const router = useRouter();
  const { id } = router.query;
  const [event, setEvent] = useState(null);
  const [title, setTitle] = useState('');
  const [description, setDescription] = useState('');
  const [date, setDate] = useState('');
  const [time, setTime] = useState('');
  const [venue, setVenue] = useState('');
  const [ticketInfo, setTicketInfo] = useState('');

  useEffect(() => {
    if (id) {
      axios.get(`/api/events/${id}`)
        .then(response => {
          const eventData = response.data;
          setEvent(eventData);
          setTitle(eventData.title);
          setDescription(eventData.description);
          setDate(eventData.date);
          setTime(eventData.time);
          setVenue(eventData.venue);
          setTicketInfo(eventData.ticketInfo);
        })
        .catch(error => console.error('Error fetching event:', error));
    }
  }, [id]);

  const handleEditEvent = async (e) => {
    e.preventDefault();

    try {
      await axios.put(`/api/events/${id}`, { title, description, date, time, venue, ticketInfo });
      router.push('/organizer/manage-events');
    } catch (err) {
      console.error(err);
      alert('Error editing event');
    }
  };

  if (!event) return <div>Loading...</div>;

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Edit Event</h1>
      <form onSubmit={handleEditEvent}>
        <div className="mb-4">
          <label className="block text-gray-700">Title</label>
          <input
            type="text"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Description</label>
          <textarea
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          ></textarea>
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Date</label>
          <input
            type="date"
            value={date}
            onChange={(e) => setDate(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Time</label>
          <input
            type="time"
            value={time}
            onChange={(e) => setTime(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Venue</label>
          <input
            type="text"
            value={venue}
            onChange={(e) => setVenue(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Ticket Information</label>
          <input
            type="text"
            value={ticketInfo}
            onChange={(e) => setTicketInfo(e.target.value)}
            className="w-full px-3 py-2 border rounded"
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Edit Event
        </button>
      </form>
    </div>
  );
};

export default EditEvent;
```

#### `pages/organizer/edit-event.js`
```javascript
import EditEvent from '../../components/Organizer/EditEvent';

const EditEventPage = () => {
  return (
    <div>
      <EditEvent

 />
    </div>
  );
};

export default EditEventPage;
```

### 3. Delete Event

#### `components/Organizer/DeleteEvent.js`
```javascript
import axios from 'axios';
import { useRouter } from 'next/router';

const DeleteEvent = ({ eventId }) => {
  const router = useRouter();

  const handleDeleteEvent = async () => {
    try {
      await axios.delete(`/api/events/${eventId}`);
      router.push('/organizer/manage-events');
    } catch (err) {
      console.error(err);
      alert('Error deleting event');
    }
  };

  return (
    <button
      onClick={handleDeleteEvent}
      className="bg-red-500 text-white py-2 px-4 rounded hover:bg-red-700"
    >
      Delete Event
    </button>
  );
};

export default DeleteEvent;
```

### 4. Manage Own Events

#### `components/Organizer/ManageOwnEvents.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import Link from 'next/link';

const ManageOwnEvents = () => {
  const [events, setEvents] = useState([]);

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/events/mine');
      setEvents(response.data);
    };

    fetchEvents();
  }, []);

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Manage My Events</h1>
      <div>
        {events.map((event) => (
          <div key={event.id} className="mb-4 p-4 border rounded">
            <h2 className="text-2xl font-bold">{event.title}</h2>
            <p>{event.description}</p>
            <p>{new Date(event.date).toLocaleDateString()} {event.time}</p>
            <p>{event.venue}</p>
            <div className="flex space-x-4 mt-4">
              <Link href={`/organizer/edit-event?id=${event.id}`}>
                <a className="bg-green-500 text-white py-2 px-4 rounded hover:bg-green-700">Edit</a>
              </Link>
              <DeleteEvent eventId={event.id} />
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default ManageOwnEvents;
```

### 5. View Event

#### `components/Event/EventDetails.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const EventDetails = () => {
  const router = useRouter();
  const { id } = router.query;
  const [event, setEvent] = useState(null);

  useEffect(() => {
    if (id) {
      axios.get(`/api/events/${id}`)
        .then(response => {
          setEvent(response.data);
        })
        .catch(error => console.error('Error fetching event:', error));
    }
  }, [id]);

  if (!event) return <div>Loading...</div>;

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">{event.title}</h1>
      <p className="mb-4">{event.description}</p>
      <p className="mb-2">Date: {new Date(event.date).toLocaleDateString()}</p>
      <p className="mb-2">Time: {event.time}</p>
      <p className="mb-2">Venue: {event.venue}</p>
      <p className="mb-2">Tickets: {event.ticketInfo}</p>
    </div>
  );
};

export default EventDetails;
```

#### `pages/events/[id].js`
```javascript
import EventDetails from '../../components/Event/EventDetails';

const EventDetailsPage = () => {
  return (
    <div>
      <EventDetails />
    </div>
  );
};

export default EventDetailsPage;
```

### 6. Search Events

#### `components/Event/SearchEvents.js`
```javascript
import { useState } from 'react';
import axios from 'axios';

const SearchEvents = () => {
  const [query, setQuery] = useState('');
  const [events, setEvents] = useState([]);

  const handleSearch = async (e) => {
    e.preventDefault();

    try {
      const response = await axios.get(`/api/events/search?query=${query}`);
      setEvents(response.data);
    } catch (err) {
      console.error(err);
      alert('Error searching events');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Search Events</h1>
      <form onSubmit={handleSearch} className="mb-6">
        <input
          type="text"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          className="w-full px-3 py-2 border rounded mb-4"
          placeholder="Search by title, date, location..."
          required
        />
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Search
        </button>
      </form>
      <div>
        {events.map((event) => (
          <div key={event.id} className="mb-4 p-4 border rounded">
            <h2 className="text-2xl font-bold">{event.title}</h2>
            <p>{event.description}</p>
            <p>{new Date(event.date).toLocaleDateString()} {event.time}</p>
            <p>{event.venue}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default SearchEvents;
```

#### `pages/events/search.js`
```javascript
import SearchEvents from '../../components/Event/SearchEvents';

const SearchEventsPage = () => {
  return (
    <div>
      <SearchEvents />
    </div>
  );
};

export default SearchEventsPage;
```

### Navigation and Authorization
Ensure you have navigation links set up and proper authorization checks for each role to access specific pages.

### Styles
Make sure Tailwind CSS is properly configured in your `globals.css`.

With these components and pages, you can build a comprehensive event management system frontend using Next.js and Tailwind CSS.

To implement ticket management features in the frontend using Next.js and Tailwind CSS, you need components and pages for creating tickets, purchasing tickets, and viewing purchased tickets. Below is the example setup for these functionalities.

### Project Structure
```
event-management-frontend
├── components
│   ├── Organizer
│   │   ├── CreateTickets.js
│   ├── Attendee
│   │   ├── PurchaseTickets.js
│   │   ├── ViewTickets.js
├── pages
│   ├── organizer
│   │   ├── create-tickets.js
│   ├── attendee
│   │   ├── purchase-tickets.js
│   │   ├── view-tickets.js
└── styles
    └── globals.css
```

### 1. Create Tickets

#### `components/Organizer/CreateTickets.js`
```javascript
import { useState } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const CreateTickets = () => {
  const [eventId, setEventId] = useState('');
  const [ticketType, setTicketType] = useState('');
  const [price, setPrice] = useState('');
  const [quantity, setQuantity] = useState('');
  const router = useRouter();

  const handleCreateTickets = async (e) => {
    e.preventDefault();

    try {
      await axios.post(`/api/events/${eventId}/tickets`, { ticketType, price, quantity });
      router.push('/organizer/manage-events');
    } catch (err) {
      console.error(err);
      alert('Error creating tickets');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Create Tickets</h1>
      <form onSubmit={handleCreateTickets}>
        <div className="mb-4">
          <label className="block text-gray-700">Event ID</label>
          <input
            type="text"
            value={eventId}
            onChange={(e) => setEventId(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Ticket Type</label>
          <input
            type="text"
            value={ticketType}
            onChange={(e) => setTicketType(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Price</label>
          <input
            type="number"
            value={price}
            onChange={(e) => setPrice(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <div className="mb-4">
          <label className="block text-gray-700">Quantity</label>
          <input
            type="number"
            value={quantity}
            onChange={(e) => setQuantity(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          />
        </div>
        <button
          type="submit"
          className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
        >
          Create Tickets
        </button>
      </form>
    </div>
  );
};

export default CreateTickets;
```

#### `pages/organizer/create-tickets.js`
```javascript
import CreateTickets from '../../components/Organizer/CreateTickets';

const CreateTicketsPage = () => {
  return (
    <div>
      <CreateTickets />
    </div>
  );
};

export default CreateTicketsPage;
```

### 2. Purchase Tickets

#### `components/Attendee/PurchaseTickets.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const PurchaseTickets = () => {
  const [events, setEvents] = useState([]);
  const [selectedEvent, setSelectedEvent] = useState('');
  const [tickets, setTickets] = useState([]);
  const [selectedTicket, setSelectedTicket] = useState('');
  const [quantity, setQuantity] = useState(1);
  const router = useRouter();

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/events');
      setEvents(response.data);
    };

    fetchEvents();
  }, []);

  useEffect(() => {
    if (selectedEvent) {
      const fetchTickets = async () => {
        const response = await axios.get(`/api/events/${selectedEvent}/tickets`);
        setTickets(response.data);
      };

      fetchTickets();
    }
  }, [selectedEvent]);

  const handlePurchase = async (e) => {
    e.preventDefault();

    try {
      await axios.post(`/api/tickets/purchase`, { eventId: selectedEvent, ticketId: selectedTicket, quantity });
      alert('Successfully purchased tickets');
      router.push('/attendee/view-tickets');
    } catch (err) {
      console.error(err);
      alert('Error purchasing tickets');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Purchase Tickets</h1>
      <form onSubmit={handlePurchase}>
        <div className="mb-4">
          <label className="block text-gray-700">Select Event</label>
          <select
            value={selectedEvent}
            onChange={(e) => setSelectedEvent(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          >
            <option value="">Select Event</option>
            {events.map(event => (
              <option key={event.id} value={event.id}>{event.title}</option>
            ))}
          </select>
        </div>
        {selectedEvent && (
          <>
            <div className="mb-4">
              <label className="block text-gray-700">Select Ticket</label>
              <select
                value={selectedTicket}
                onChange={(e) => setSelectedTicket(e.target.value)}
                className="w-full px-3 py-2 border rounded"
                required
              >
                <option value="">Select Ticket</option>
                {tickets.map(ticket => (
                  <option key={ticket.id} value={ticket.id}>{ticket.ticketType} - ${ticket.price}</option>
                ))}
              </select>
            </div>
            <div className="mb-4">
              <label className="block text-gray-700">Quantity</label>
              <input
                type="number"
                value={quantity}
                onChange={(e) => setQuantity(e.target.value)}
                className="w-full px-3 py-2 border rounded"
                min="1"
                required
              />
            </div>
            <button
              type="submit"
              className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
            >
              Purchase Tickets
            </button>
          </>
        )}
      </form>
    </div>
  );
};

export default PurchaseTickets;
```

#### `pages/attendee/purchase-tickets.js`
```javascript
import PurchaseTickets from '../../components/Attendee/PurchaseTickets';

const PurchaseTicketsPage = () => {
  return (
    <div>
      <PurchaseTickets />
    </div>
  );
};

export default PurchaseTicketsPage;
```

### 3. View Tickets

#### `components/Attendee/ViewTickets.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const ViewTickets = () => {
  const [tickets, setTickets] = useState([]);

  useEffect(() => {
    const fetchTickets = async () => {
      const response = await axios.get('/api/tickets');
      setTickets(response.data);
    };

    fetchTickets();
  }, []);

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">My Tickets</h1>
      <div>
        {tickets.map((ticket) => (
          <div key={ticket.id} className="mb-4 p-4 border rounded">
            <h2 className="text-2xl font-bold">{ticket.event.title}</h2>
            <p>Type: {ticket.ticketType}</p>
            <p>Price: ${ticket.price}</p>
            <p>Quantity: {ticket.quantity}</p>
            <p>Date: {new Date(ticket.event.date).toLocaleDateString()}</p>
            <p>Time: {ticket.event.time}</p>
            <p>Venue: {ticket.event.venue}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default ViewTickets;
```

#### `pages/attendee/view-tickets.js`
```javascript
import ViewTickets from '../../components/Attendee/ViewTickets';

const ViewTicketsPage = () => {
  return (
    <div>
      <ViewTickets />
    </div>
  );
};

export default ViewTicketsPage;
```

### Navigation and Authorization
Ensure you have navigation links set up and proper authorization checks

 for each role to access specific pages.

### Styles
Make sure Tailwind CSS is properly configured in your `globals.css`.

With these components and pages, you can build a comprehensive ticket management system frontend using Next.js and Tailwind CSS.

To implement a notification system in the frontend using Next.js and Tailwind CSS, you'll need components for displaying in-app notifications and mechanisms to trigger email notifications (typically handled by the backend). Below is an example setup for in-app notifications and placeholders for triggering email notifications.

### Project Structure
```
event-management-frontend
├── components
│   ├── Notifications
│   │   ├── InAppNotifications.js
├── pages
│   ├── notifications
│   │   ├── index.js
└── styles
    └── globals.css
```

### 1. In-App Notifications

#### `components/Notifications/InAppNotifications.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const InAppNotifications = () => {
  const [notifications, setNotifications] = useState([]);

  useEffect(() => {
    const fetchNotifications = async () => {
      const response = await axios.get('/api/notifications');
      setNotifications(response.data);
    };

    fetchNotifications();
  }, []);

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Notifications</h1>
      <div>
        {notifications.map((notification) => (
          <div key={notification.id} className="mb-4 p-4 border rounded bg-gray-100">
            <h2 className="text-2xl font-bold">{notification.title}</h2>
            <p>{notification.message}</p>
            <p className="text-sm text-gray-500">{new Date(notification.createdAt).toLocaleString()}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default InAppNotifications;
```

#### `pages/notifications/index.js`
```javascript
import InAppNotifications from '../../components/Notifications/InAppNotifications';

const NotificationsPage = () => {
  return (
    <div>
      <InAppNotifications />
    </div>
  );
};

export default NotificationsPage;
```

### Triggering Email Notifications
Email notifications are typically handled by the backend. Here's an example of how you might trigger email notifications from the frontend by making API calls to your backend.

### Example: Triggering Email Notification on Ticket Purchase

#### `components/Attendee/PurchaseTickets.js` (Modified)
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';

const PurchaseTickets = () => {
  const [events, setEvents] = useState([]);
  const [selectedEvent, setSelectedEvent] = useState('');
  const [tickets, setTickets] = useState([]);
  const [selectedTicket, setSelectedTicket] = useState('');
  const [quantity, setQuantity] = useState(1);
  const router = useRouter();

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/events');
      setEvents(response.data);
    };

    fetchEvents();
  }, []);

  useEffect(() => {
    if (selectedEvent) {
      const fetchTickets = async () => {
        const response = await axios.get(`/api/events/${selectedEvent}/tickets`);
        setTickets(response.data);
      };

      fetchTickets();
    }
  }, [selectedEvent]);

  const handlePurchase = async (e) => {
    e.preventDefault();

    try {
      await axios.post(`/api/tickets/purchase`, { eventId: selectedEvent, ticketId: selectedTicket, quantity });
      alert('Successfully purchased tickets');

      // Trigger email notification
      await axios.post(`/api/notifications/email`, {
        type: 'TICKET_PURCHASE',
        userId: 'current_user_id',  // Replace with actual user ID
        eventId: selectedEvent,
        ticketId: selectedTicket,
      });

      router.push('/attendee/view-tickets');
    } catch (err) {
      console.error(err);
      alert('Error purchasing tickets');
    }
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Purchase Tickets</h1>
      <form onSubmit={handlePurchase}>
        <div className="mb-4">
          <label className="block text-gray-700">Select Event</label>
          <select
            value={selectedEvent}
            onChange={(e) => setSelectedEvent(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          >
            <option value="">Select Event</option>
            {events.map(event => (
              <option key={event.id} value={event.id}>{event.title}</option>
            ))}
          </select>
        </div>
        {selectedEvent && (
          <>
            <div className="mb-4">
              <label className="block text-gray-700">Select Ticket</label>
              <select
                value={selectedTicket}
                onChange={(e) => setSelectedTicket(e.target.value)}
                className="w-full px-3 py-2 border rounded"
                required
              >
                <option value="">Select Ticket</option>
                {tickets.map(ticket => (
                  <option key={ticket.id} value={ticket.id}>{ticket.ticketType} - ${ticket.price}</option>
                ))}
              </select>
            </div>
            <div className="mb-4">
              <label className="block text-gray-700">Quantity</label>
              <input
                type="number"
                value={quantity}
                onChange={(e) => setQuantity(e.target.value)}
                className="w-full px-3 py-2 border rounded"
                min="1"
                required
              />
            </div>
            <button
              type="submit"
              className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
            >
              Purchase Tickets
            </button>
          </>
        )}
      </form>
    </div>
  );
};

export default PurchaseTickets;
```

### Summary
- **In-App Notifications:** The `InAppNotifications` component displays real-time notifications. The notifications are fetched from the backend using an API call.
- **Email Notifications:** Email notifications are triggered by making an API call to the backend whenever an important action occurs (e.g., ticket purchase).

Make sure to implement the necessary backend logic to handle these API endpoints and send emails.

To integrate a payment gateway in your frontend for ticket purchases, you can use popular options like Stripe. Below is an example of how to integrate Stripe into your Next.js application for handling ticket purchases.

### Project Structure
```
event-management-frontend
├── components
│   ├── Attendee
│   │   ├── PurchaseTickets.js
│   │   ├── CheckoutForm.js
├── pages
│   ├── attendee
│   │   ├── purchase-tickets.js
│   │   ├── success.js
└── styles
    └── globals.css
```

### 1. Setting Up Stripe

First, install the necessary Stripe packages:

```bash
npm install @stripe/stripe-js @stripe/react-stripe-js
```

### 2. Checkout Form Component

#### `components/Attendee/CheckoutForm.js`
```javascript
import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
import axios from 'axios';
import { useRouter } from 'next/router';
import { useState } from 'react';

const CheckoutForm = ({ eventId, ticketId, quantity }) => {
  const stripe = useStripe();
  const elements = useElements();
  const router = useRouter();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

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

    if (!stripe || !elements) {
      return;
    }

    const cardElement = elements.getElement(CardElement);

    try {
      const { data: clientSecret } = await axios.post('/api/create-payment-intent', {
        eventId,
        ticketId,
        quantity,
      });

      const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
        payment_method: {
          card: cardElement,
          billing_details: {
            name: 'Test User',
          },
        },
      });

      if (stripeError) {
        setError(`Payment failed: ${stripeError.message}`);
        setLoading(false);
        return;
      }

      if (paymentIntent.status === 'succeeded') {
        alert('Payment successful');
        router.push('/attendee/success');
      }
    } catch (error) {
      setError(`Payment failed: ${error.message}`);
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="w-full max-w-lg mx-auto p-6">
      <CardElement className="border p-4 rounded mb-4" />
      {error && <div className="text-red-500 mb-4">{error}</div>}
      <button
        type="submit"
        disabled={!stripe || loading}
        className={`w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700 ${loading && 'opacity-50 cursor-not-allowed'}`}
      >
        {loading ? 'Processing...' : 'Pay Now'}
      </button>
    </form>
  );
};

export default CheckoutForm;
```

### 3. Purchase Tickets Component

#### `components/Attendee/PurchaseTickets.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { useRouter } from 'next/router';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import CheckoutForm from './CheckoutForm';

const stripePromise = loadStripe('your-publishable-key-from-stripe');

const PurchaseTickets = () => {
  const [events, setEvents] = useState([]);
  const [selectedEvent, setSelectedEvent] = useState('');
  const [tickets, setTickets] = useState([]);
  const [selectedTicket, setSelectedTicket] = useState('');
  const [quantity, setQuantity] = useState(1);
  const [checkout, setCheckout] = useState(false);
  const router = useRouter();

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/events');
      setEvents(response.data);
    };

    fetchEvents();
  }, []);

  useEffect(() => {
    if (selectedEvent) {
      const fetchTickets = async () => {
        const response = await axios.get(`/api/events/${selectedEvent}/tickets`);
        setTickets(response.data);
      };

      fetchTickets();
    }
  }, [selectedEvent]);

  const handlePurchase = async (e) => {
    e.preventDefault();
    setCheckout(true);
  };

  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Purchase Tickets</h1>
      <form onSubmit={handlePurchase}>
        <div className="mb-4">
          <label className="block text-gray-700">Select Event</label>
          <select
            value={selectedEvent}
            onChange={(e) => setSelectedEvent(e.target.value)}
            className="w-full px-3 py-2 border rounded"
            required
          >
            <option value="">Select Event</option>
            {events.map(event => (
              <option key={event.id} value={event.id}>{event.title}</option>
            ))}
          </select>
        </div>
        {selectedEvent && (
          <>
            <div className="mb-4">
              <label className="block text-gray-700">Select Ticket</label>
              <select
                value={selectedTicket}
                onChange={(e) => setSelectedTicket(e.target.value)}
                className="w-full px-3 py-2 border rounded"
                required
              >
                <option value="">Select Ticket</option>
                {tickets.map(ticket => (
                  <option key={ticket.id} value={ticket.id}>{ticket.ticketType} - ${ticket.price}</option>
                ))}
              </select>
            </div>
            <div className="mb-4">
              <label className="block text-gray-700">Quantity</label>
              <input
                type="number"
                value={quantity}
                onChange={(e) => setQuantity(e.target.value)}
                className="w-full px-3 py-2 border rounded"
                min="1"
                required
              />
            </div>
            <button
              type="submit"
              className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-700"
            >
              Proceed to Checkout
            </button>
          </>
        )}
      </form>
      {checkout && (
        <Elements stripe={stripePromise}>
          <CheckoutForm eventId={selectedEvent} ticketId={selectedTicket} quantity={quantity} />
        </Elements>
      )}
    </div>
  );
};

export default PurchaseTickets;
```

#### `pages/attendee/purchase-tickets.js`
```javascript
import PurchaseTickets from '../../components/Attendee/PurchaseTickets';

const PurchaseTicketsPage = () => {
  return (
    <div>
      <PurchaseTickets />
    </div>
  );
};

export default PurchaseTicketsPage;
```

### 4. Success Page

#### `pages/attendee/success.js`
```javascript
const SuccessPage = () => {
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Payment Successful</h1>
      <p className="mb-4">Thank you for your purchase. You will receive an email confirmation shortly.</p>
      <a href="/attendee/view-tickets" className="text-blue-500 hover:underline">View Your Tickets</a>
    </div>
  );
};

export default SuccessPage;
```

### Summary
- **Checkout Form:** The `CheckoutForm` component handles the Stripe payment process.
- **Purchase Tickets:** The `PurchaseTickets` component handles the ticket selection and triggers the checkout process.
- **Success Page:** A simple page to display after successful payment.

This setup integrates Stripe into your Next.js application for handling payments. Ensure you have the necessary backend setup to create payment intents and handle webhook events from Stripe for a complete integration.

To create dashboards for Admin, Organizer, and Attendee roles in your Next.js application using Tailwind CSS, you will need to set up the structure and components for each dashboard. Each dashboard will have different views and functionalities according to the role.

### Project Structure
```
event-management-frontend
├── components
│   ├── Admin
│   │   ├── AdminDashboard.js
│   ├── Organizer
│   │   ├── OrganizerDashboard.js
│   ├── Attendee
│   │   ├── AttendeeDashboard.js
├── pages
│   ├── admin
│   │   ├── dashboard.js
│   ├── organizer
│   │   ├── dashboard.js
│   ├── attendee
│   │   ├── dashboard.js
└── styles
    └── globals.css
```

### 1. Admin Dashboard

#### `components/Admin/AdminDashboard.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const AdminDashboard = () => {
  const [metrics, setMetrics] = useState({});
  const [users, setUsers] = useState([]);
  const [events, setEvents] = useState([]);

  useEffect(() => {
    const fetchMetrics = async () => {
      const response = await axios.get('/api/admin/metrics');
      setMetrics(response.data);
    };

    const fetchUsers = async () => {
      const response = await axios.get('/api/admin/users');
      setUsers(response.data);
    };

    const fetchEvents = async () => {
      const response = await axios.get('/api/admin/events');
      setEvents(response.data);
    };

    fetchMetrics();
    fetchUsers();
    fetchEvents();
  }, []);

  return (
    <div className="max-w-7xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Admin Dashboard</h1>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">System Metrics</h2>
        <div className="grid grid-cols-3 gap-6">
          <div className="bg-white p-6 rounded shadow">
            <h3 className="text-xl font-bold">Total Users</h3>
            <p className="text-3xl">{metrics.totalUsers}</p>
          </div>
          <div className="bg-white p-6 rounded shadow">
            <h3 className="text-xl font-bold">Total Events</h3>
            <p className="text-3xl">{metrics.totalEvents}</p>
          </div>
          <div className="bg-white p-6 rounded shadow">
            <h3 className="text-xl font-bold">Total Tickets Sold</h3>
            <p className="text-3xl">{metrics.totalTicketsSold}</p>
          </div>
        </div>
      </div>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">User Management</h2>
        <table className="min-w-full bg-white border">
          <thead>
            <tr>
              <th className="border px-4 py-2">ID</th>
              <th className="border px-4 py-2">Name</th>
              <th className="border px-4 py-2">Email</th>
              <th className="border px-4 py-2">Role</th>
            </tr>
          </thead>
          <tbody>
            {users.map(user => (
              <tr key={user.id}>
                <td className="border px-4 py-2">{user.id}</td>
                <td className="border px-4 py-2">{user.name}</td>
                <td className="border px-4 py-2">{user.email}</td>
                <td className="border px-4 py-2">{user.role}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">Event Management</h2>
        <table className="min-w-full bg-white border">
          <thead>
            <tr>
              <th className="border px-4 py-2">ID</th>
              <th className="border px-4 py-2">Title</th>
              <th className="border px-4 py-2">Organizer</th>
              <th className="border px-4 py-2">Date</th>
            </tr>
          </thead>
          <tbody>
            {events.map(event => (
              <tr key={event.id}>
                <td className="border px-4 py-2">{event.id}</td>
                <td className="border px-4 py-2">{event.title}</td>
                <td className="border px-4 py-2">{event.organizer}</td>
                <td className="border px-4 py-2">{new Date(event.date).toLocaleDateString()}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

export default AdminDashboard;
```

#### `pages/admin/dashboard.js`
```javascript
import AdminDashboard from '../../components/Admin/AdminDashboard';

const AdminDashboardPage = () => {
  return (
    <div>
      <AdminDashboard />
    </div>
  );
};

export default AdminDashboardPage;
```

### 2. Organizer Dashboard

#### `components/Organizer/OrganizerDashboard.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const OrganizerDashboard = () => {
  const [events, setEvents] = useState([]);
  const [ticketSales, setTicketSales] = useState([]);

  useEffect(() => {
    const fetchEvents = async () => {
      const response = await axios.get('/api/organizer/events');
      setEvents(response.data);
    };

    const fetchTicketSales = async () => {
      const response = await axios.get('/api/organizer/ticket-sales');
      setTicketSales(response.data);
    };

    fetchEvents();
    fetchTicketSales();
  }, []);

  return (
    <div className="max-w-7xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Organizer Dashboard</h1>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">Your Events</h2>
        <table className="min-w-full bg-white border">
          <thead>
            <tr>
              <th className="border px-4 py-2">ID</th>
              <th className="border px-4 py-2">Title</th>
              <th className="border px-4 py-2">Date</th>
              <th className="border px-4 py-2">Venue</th>
              <th className="border px-4 py-2">Tickets Sold</th>
            </tr>
          </thead>
          <tbody>
            {events.map(event => (
              <tr key={event.id}>
                <td className="border px-4 py-2">{event.id}</td>
                <td className="border px-4 py-2">{event.title}</td>
                <td className="border px-4 py-2">{new Date(event.date).toLocaleDateString()}</td>
                <td className="border px-4 py-2">{event.venue}</td>
                <td className="border px-4 py-2">{ticketSales[event.id]}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

export default OrganizerDashboard;
```

#### `pages/organizer/dashboard.js`
```javascript
import OrganizerDashboard from '../../components/Organizer/OrganizerDashboard';

const OrganizerDashboardPage = () => {
  return (
    <div>
      <OrganizerDashboard />
    </div>
  );
};

export default OrganizerDashboardPage;
```

### 3. Attendee Dashboard

#### `components/Attendee/AttendeeDashboard.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';

const AttendeeDashboard = () => {
  const [registeredEvents, setRegisteredEvents] = useState([]);
  const [purchasedTickets, setPurchasedTickets] = useState([]);

  useEffect(() => {
    const fetchRegisteredEvents = async () => {
      const response = await axios.get('/api/attendee/registered-events');
      setRegisteredEvents(response.data);
    };

    const fetchPurchasedTickets = async () => {
      const response = await axios.get('/api/attendee/purchased-tickets');
      setPurchasedTickets(response.data);
    };

    fetchRegisteredEvents();
    fetchPurchasedTickets();
  }, []);

  return (
    <div className="max-w-7xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Attendee Dashboard</h1>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">Registered Events</h2>
        <table className="min-w-full bg-white border">
          <thead>
            <tr>
              <th className="border

 px-4 py-2">ID</th>
              <th className="border px-4 py-2">Title</th>
              <th className="border px-4 py-2">Date</th>
              <th className="border px-4 py-2">Venue</th>
            </tr>
          </thead>
          <tbody>
            {registeredEvents.map(event => (
              <tr key={event.id}>
                <td className="border px-4 py-2">{event.id}</td>
                <td className="border px-4 py-2">{event.title}</td>
                <td className="border px-4 py-2">{new Date(event.date).toLocaleDateString()}</td>
                <td className="border px-4 py-2">{event.venue}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">Purchased Tickets</h2>
        <table className="min-w-full bg-white border">
          <thead>
            <tr>
              <th className="border px-4 py-2">Ticket ID</th>
              <th className="border px-4 py-2">Event</th>
              <th className="border px-4 py-2">Quantity</th>
              <th className="border px-4 py-2">Price</th>
            </tr>
          </thead>
          <tbody>
            {purchasedTickets.map(ticket => (
              <tr key={ticket.id}>
                <td className="border px-4 py-2">{ticket.id}</td>
                <td className="border px-4 py-2">{ticket.eventTitle}</td>
                <td className="border px-4 py-2">{ticket.quantity}</td>
                <td className="border px-4 py-2">${ticket.price}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

export default AttendeeDashboard;
```

#### `pages/attendee/dashboard.js`
```javascript
import AttendeeDashboard from '../../components/Attendee/AttendeeDashboard';

const AttendeeDashboardPage = () => {
  return (
    <div>
      <AttendeeDashboard />
    </div>
  );
};

export default AttendeeDashboardPage;
```

### Summary
- **Admin Dashboard:** Displays system metrics, user management, and event management.
- **Organizer Dashboard:** Shows organizer's events and ticket sales.
- **Attendee Dashboard:** Shows registered events and purchased tickets.

Each dashboard fetches data from the backend using Axios and displays it in tables. Tailwind CSS is used for styling. Make sure your backend APIs are set up to provide the necessary data for each dashboard.

To implement analytics for events and users in your Next.js application, you can use charting libraries such as Chart.js or Recharts. For this example, we'll use Recharts, a popular charting library for React, to display event performance and user engagement insights.

### Project Structure
```
event-management-frontend
├── components
│   ├── Analytics
│   │   ├── EventAnalytics.js
│   │   ├── UserAnalytics.js
├── pages
│   ├── analytics
│   │   ├── event.js
│   │   ├── user.js
└── styles
    └── globals.css
```

### 1. Install Recharts

First, install Recharts:

```bash
npm install recharts
```

### 2. Event Analytics Component

#### `components/Analytics/EventAnalytics.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { BarChart, Bar, XAxis, YAxis, Tooltip, CartesianGrid, ResponsiveContainer } from 'recharts';

const EventAnalytics = () => {
  const [ticketSales, setTicketSales] = useState([]);
  const [attendeeDemographics, setAttendeeDemographics] = useState([]);

  useEffect(() => {
    const fetchTicketSales = async () => {
      const response = await axios.get('/api/analytics/ticket-sales');
      setTicketSales(response.data);
    };

    const fetchAttendeeDemographics = async () => {
      const response = await axios.get('/api/analytics/attendee-demographics');
      setAttendeeDemographics(response.data);
    };

    fetchTicketSales();
    fetchAttendeeDemographics();
  }, []);

  return (
    <div className="max-w-7xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">Event Analytics</h1>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">Ticket Sales</h2>
        <ResponsiveContainer width="100%" height={400}>
          <BarChart data={ticketSales}>
            <CartesianGrid strokeDasharray="3 3" />
            <XAxis dataKey="event" />
            <YAxis />
            <Tooltip />
            <Bar dataKey="sales" fill="#8884d8" />
          </BarChart>
        </ResponsiveContainer>
      </div>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">Attendee Demographics</h2>
        <ResponsiveContainer width="100%" height={400}>
          <BarChart data={attendeeDemographics}>
            <CartesianGrid strokeDasharray="3 3" />
            <XAxis dataKey="ageGroup" />
            <YAxis />
            <Tooltip />
            <Bar dataKey="attendees" fill="#82ca9d" />
          </BarChart>
        </ResponsiveContainer>
      </div>
    </div>
  );
};

export default EventAnalytics;
```

### 3. User Analytics Component

#### `components/Analytics/UserAnalytics.js`
```javascript
import { useState, useEffect } from 'react';
import axios from 'axios';
import { LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid, ResponsiveContainer } from 'recharts';

const UserAnalytics = () => {
  const [userBehavior, setUserBehavior] = useState([]);
  const [userEngagement, setUserEngagement] = useState([]);

  useEffect(() => {
    const fetchUserBehavior = async () => {
      const response = await axios.get('/api/analytics/user-behavior');
      setUserBehavior(response.data);
    };

    const fetchUserEngagement = async () => {
      const response = await axios.get('/api/analytics/user-engagement');
      setUserEngagement(response.data);
    };

    fetchUserBehavior();
    fetchUserEngagement();
  }, []);

  return (
    <div className="max-w-7xl mx-auto mt-10">
      <h1 className="text-3xl font-bold mb-6">User Analytics</h1>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">User Behavior</h2>
        <ResponsiveContainer width="100%" height={400}>
          <LineChart data={userBehavior}>
            <CartesianGrid strokeDasharray="3 3" />
            <XAxis dataKey="date" />
            <YAxis />
            <Tooltip />
            <Line type="monotone" dataKey="activeUsers" stroke="#8884d8" />
          </LineChart>
        </ResponsiveContainer>
      </div>
      <div className="mb-6">
        <h2 className="text-2xl font-bold mb-4">User Engagement</h2>
        <ResponsiveContainer width="100%" height={400}>
          <LineChart data={userEngagement}>
            <CartesianGrid strokeDasharray="3 3" />
            <XAxis dataKey="date" />
            <YAxis />
            <Tooltip />
            <Line type="monotone" dataKey="engagement" stroke="#82ca9d" />
          </LineChart>
        </ResponsiveContainer>
      </div>
    </div>
  );
};

export default UserAnalytics;
```

### 4. Analytics Pages

#### `pages/analytics/event.js`
```javascript
import EventAnalytics from '../../components/Analytics/EventAnalytics';

const EventAnalyticsPage = () => {
  return (
    <div>
      <EventAnalytics />
    </div>
  );
};

export default EventAnalyticsPage;
```

#### `pages/analytics/user.js`
```javascript
import UserAnalytics from '../../components/Analytics/UserAnalytics';

const UserAnalyticsPage = () => {
  return (
    <div>
      <UserAnalytics />
    </div>
  );
};

export default UserAnalyticsPage;
```

### Summary
- **Event Analytics:** Displays insights into event performance using bar charts to show ticket sales and attendee demographics.
- **User Analytics:** Shows insights into user behavior and engagement using line charts.

Each component fetches data from the backend using Axios and displays it using Recharts. Tailwind CSS is used for styling. Ensure your backend APIs are set up to provide the necessary data for each analytic view.

Here is a detailed setup for the backend of your full-stack event management system using NestJS, Prisma, PostgreSQL, and GraphQL. Let's start with the basic setup for user authentication.

### Backend Setup with NestJS

1. **Initialize a NestJS Project**
    ```bash
    npm i -g @nestjs/cli
    nest new event-management-backend
    ```

2. **Install Required Dependencies**
    ```bash
    cd event-management-backend
    npm install @nestjs/graphql @nestjs/apollo apollo-server-express graphql
    npm install @prisma/client
    npm install bcryptjs
    npm install @nestjs/jwt passport-jwt @nestjs/passport passport
    npm install class-validator class-transformer
    ```

3. **Set Up Prisma**
    ```bash
    npx prisma init
    ```

    Update your `prisma/schema.prisma` file:
    ```prisma
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
    }

    generator client {
      provider = "prisma-client-js"
    }

    model User {
      id        Int      @id @default(autoincrement())
      email     String   @unique
      password  String
      createdAt DateTime @default(now())
      updatedAt DateTime @updatedAt
    }
    ```

    Update your `.env` file with your PostgreSQL connection string:
    ```
    DATABASE_URL="postgresql://username:password@localhost:5432/mydb"
    ```

    Run the Prisma migration:
    ```bash
    npx prisma migrate dev --name init
    ```

4. **Configure Prisma in NestJS**

    Create `prisma.module.ts`:
    ```typescript
    import { Module } from '@nestjs/common';
    import { PrismaService } from './prisma.service';

    @Module({
      providers: [PrismaService],
      exports: [PrismaService],
    })
    export class PrismaModule {}
    ```

    Create `prisma.service.ts`:
    ```typescript
    import { Injectable, OnModuleInit, INestApplication } from '@nestjs/common';
    import { PrismaClient } from '@prisma/client';

    @Injectable()
    export class PrismaService extends PrismaClient implements OnModuleInit {
      async onModuleInit() {
        await this.$connect();
      }

      async enableShutdownHooks(app: INestApplication) {
        this.$on('beforeExit', async () => {
          await app.close();
        });
      }
    }
    ```

5. **Setup Authentication Module**

    Create `auth.module.ts`:
    ```typescript
    import { Module } from '@nestjs/common';
    import { AuthService } from './auth.service';
    import { AuthResolver } from './auth.resolver';
    import { JwtModule } from '@nestjs/jwt';
    import { PassportModule } from '@nestjs/passport';
    import { PrismaModule } from '../prisma/prisma.module';
    import { JwtStrategy } from './jwt.strategy';

    @Module({
      imports: [
        PrismaModule,
        PassportModule,
        JwtModule.register({
          secret: 'your_secret_key', // use a better secret in production
          signOptions: { expiresIn: '60m' },
        }),
      ],
      providers: [AuthService, AuthResolver, JwtStrategy],
    })
    export class AuthModule {}
    ```

    Create `auth.service.ts`:
    ```typescript
    import { Injectable } from '@nestjs/common';
    import { JwtService } from '@nestjs/jwt';
    import { PrismaService } from '../prisma/prisma.service';
    import * as bcrypt from 'bcryptjs';

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

      async validateUser(email: string, password: string): Promise<any> {
        const user = await this.prisma.user.findUnique({ where: { email } });
        if (user && (await bcrypt.compare(password, user.password))) {
          const { password, ...result } = user;
          return result;
        }
        return null;
      }

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

      async signup(email: string, password: string) {
        const hashedPassword = await bcrypt.hash(password, 10);
        const user = await this.prisma.user.create({
          data: {
            email,
            password: hashedPassword,
          },
        });
        return user;
      }
    }
    ```

    Create `auth.resolver.ts`:
    ```typescript
    import { Resolver, Mutation, Args } from '@nestjs/graphql';
    import { AuthService } from './auth.service';
    import { AuthResponse } from './dto/auth-response';
    import { UserInput } from './dto/user-input';

    @Resolver()
    export class AuthResolver {
      constructor(private readonly authService: AuthService) {}

      @Mutation(() => AuthResponse)
      async login(@Args('userInput') userInput: UserInput) {
        const user = await this.authService.validateUser(userInput.email, userInput.password);
        if (!user) {
          throw new Error('Invalid credentials');
        }
        return this.authService.login(user);
      }

      @Mutation(() => AuthResponse)
      async signup(@Args('userInput') userInput: UserInput) {
        const user = await this.authService.signup(userInput.email, userInput.password);
        return this.authService.login(user);
      }
    }
    ```

    Create DTOs (`dto/auth-response.ts` and `dto/user-input.ts`):
    ```typescript
    // auth-response.ts
    import { Field, ObjectType } from '@nestjs/graphql';

    @ObjectType()
    export class AuthResponse {
      @Field()
      access_token: string;
    }
    ```

    ```typescript
    // user-input.ts
    import { InputType, Field } from '@nestjs/graphql';

    @InputType()
    export class UserInput {
      @Field()
      email: string;

      @Field()
      password: string;
    }
    ```

6. **Setup JWT Strategy**

    Create `jwt.strategy.ts`:
    ```typescript
    import { Injectable } from '@nestjs/common';
    import { PassportStrategy } from '@nestjs/passport';
    import { ExtractJwt, Strategy } from 'passport-jwt';
    import { JwtPayload } from './jwt-payload.interface';
    import { PrismaService } from '../prisma/prisma.service';

    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor(private readonly prisma: PrismaService) {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          ignoreExpiration: false,
          secretOrKey: 'your_secret_key', // use a better secret in production
        });
      }

      async validate(payload: JwtPayload) {
        const user = await this.prisma.user.findUnique({ where: { id: payload.sub } });
        if (!user) {
          throw new UnauthorizedException();
        }
        return user;
      }
    }
    ```

    Create `jwt-payload.interface.ts`:
    ```typescript
    export interface JwtPayload {
      email: string;
      sub: number;
    }
    ```

7. **Add GraphQL Module**

    Configure `graphql.module.ts`:
    ```typescript
    import { Module } from '@nestjs/common';
    import { GraphQLModule } from '@nestjs/graphql';
    import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
    import { join } from 'path';

    @Module({
      imports: [
        GraphQLModule.forRoot<ApolloDriverConfig>({
          driver: ApolloDriver,
          autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
          sortSchema: true,
        }),
      ],
    })
    export class GraphqlModule {}
    ```

8. **Integrate All Modules in App Module**

    Update `app.module.ts`:
    ```typescript
    import { Module } from '@nestjs/common';
    import { AuthModule } from './auth/auth.module';
    import { PrismaModule } from './prisma/prisma.module';
    import { GraphqlModule } from './graphql/graphql.module';

    @Module({
      imports: [
        AuthModule,
        PrismaModule,
        GraphqlModule,
      ],
    })
    export class AppModule {}
    ```

### Running the Backend

1. **Start the NestJS Server**
    ```bash
    npm run start:dev
    ```

2. **Test the GraphQL API**

    Access the GraphQL playground at `http://localhost:3000/graphql` and test the authentication queries and mutations:

    ```graphql
    mutation {
      signup(userInput: {email: "test@example.com", password: "password"}) {
        access_token
      }
    }

    mutation {
      login(userInput: {email: "test@example.com", password: "password"}) {
        access_token
      }
    }
    ```

This setup provides the foundational authentication system. You can now build upon this by adding other features like event management, ticket management, notifications, and more.

Sure, let's extend the backend to support user roles and permissions. We'll add role-based access control to our authentication system. Here’s how we can achieve that:

1. **Update Prisma Schema for Roles**

   Add roles and related fields to `prisma/schema.prisma`:
   ```prisma
   model User {
     id        Int      @id @default(autoincrement())
     email     String   @unique
     password  String
     role      Role     @default(ATTENDEE)
     createdAt DateTime @default(now())
     updatedAt DateTime @updatedAt
   }

   enum Role {
     ADMIN
     ORGANIZER
     ATTENDEE
   }
   ```

   Run the Prisma migration:
   ```bash
   npx prisma migrate dev --name add-roles
   ```

2. **Update User Registration to Assign Roles**

   Update `auth.service.ts` to assign roles during signup:
   ```typescript
   import { Injectable } from '@nestjs/common';
   import { JwtService } from '@nestjs/jwt';
   import { PrismaService } from '../prisma/prisma.service';
   import * as bcrypt from 'bcryptjs';
   import { Role } from '@prisma/client';

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

     async validateUser(email: string, password: string): Promise<any> {
       const user = await this.prisma.user.findUnique({ where: { email } });
       if (user && (await bcrypt.compare(password, user.password))) {
         const { password, ...result } = user;
         return result;
       }
       return null;
     }

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

     async signup(email: string, password: string, role: Role) {
       const hashedPassword = await bcrypt.hash(password, 10);
       const user = await this.prisma.user.create({
         data: {
           email,
           password: hashedPassword,
           role,
         },
       });
       return user;
     }
   }
   ```

   Update `auth.resolver.ts` to accept role during signup:
   ```typescript
   import { Resolver, Mutation, Args } from '@nestjs/graphql';
   import { AuthService } from './auth.service';
   import { AuthResponse } from './dto/auth-response';
   import { UserInput } from './dto/user-input';
   import { Role } from '@prisma/client';

   @Resolver()
   export class AuthResolver {
     constructor(private readonly authService: AuthService) {}

     @Mutation(() => AuthResponse)
     async login(@Args('userInput') userInput: UserInput) {
       const user = await this.authService.validateUser(userInput.email, userInput.password);
       if (!user) {
         throw new Error('Invalid credentials');
       }
       return this.authService.login(user);
     }

     @Mutation(() => AuthResponse)
     async signup(@Args('userInput') userInput: UserInput, @Args('role') role: Role) {
       const user = await this.authService.signup(userInput.email, userInput.password, role);
       return this.authService.login(user);
     }
   }
   ```

3. **Create Guard for Role-Based Authorization**

   Create `roles.guard.ts`:
   ```typescript
   import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
   import { Reflector } from '@nestjs/core';
   import { Role } from '@prisma/client';

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

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

   Create `roles.decorator.ts`:
   ```typescript
   import { SetMetadata } from '@nestjs/common';
   import { Role } from '@prisma/client';

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

4. **Protect Routes with Role-Based Guards**

   Update event-related resolvers and services to use the role-based guard:

   Example for event management (`events.module.ts`, `events.service.ts`, `events.resolver.ts`):

   Create `events.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { EventsService } from './events.service';
   import { EventsResolver } from './events.resolver';
   import { PrismaModule } from '../prisma/prisma.module';

   @Module({
     imports: [PrismaModule],
     providers: [EventsService, EventsResolver],
   })
   export class EventsModule {}
   ```

   Create `events.service.ts`:
   ```typescript
   import { Injectable } from '@nestjs/common';
   import { PrismaService } from '../prisma/prisma.service';

   @Injectable()
   export class EventsService {
     constructor(private readonly prisma: PrismaService) {}

     // Add methods for event creation, deletion, etc.
   }
   ```

   Create `events.resolver.ts`:
   ```typescript
   import { Resolver, Mutation, Args, Query } from '@nestjs/graphql';
   import { EventsService } from './events.service';
   import { UseGuards } from '@nestjs/common';
   import { RolesGuard } from '../auth/roles.guard';
   import { Roles } from '../auth/roles.decorator';
   import { Role } from '@prisma/client';

   @Resolver()
   export class EventsResolver {
     constructor(private readonly eventsService: EventsService) {}

     @Mutation(() => Boolean)
     @Roles(Role.ORGANIZER)
     @UseGuards(RolesGuard)
     async createEvent(
       @Args('title') title: string,
       @Args('description') description: string,
       // Add other event fields
     ) {
       // Call service method to create event
       return true;
     }

     @Mutation(() => Boolean)
     @Roles(Role.ORGANIZER)
     @UseGuards(RolesGuard)
     async deleteEvent(@Args('id') id: number) {
       // Call service method to delete event
       return true;
     }

     @Query(() => [Event])
     async events() {
       // Call service method to get events
       return [];
     }
   }
   ```

5. **Integrate Event Module in App Module**

   Update `app.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { AuthModule } from './auth/auth.module';
   import { PrismaModule } from './prisma/prisma.module';
   import { GraphqlModule } from './graphql/graphql.module';
   import { EventsModule } from './events/events.module';

   @Module({
     imports: [
       AuthModule,
       PrismaModule,
       GraphqlModule,
       EventsModule,
     ],
   })
   export class AppModule {}
   ```

### Running the Backend

1. **Start the NestJS Server**
   ```bash
   npm run start:dev
   ```

2. **Test Role-Based Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the role-based mutations and queries:

   ```graphql
   mutation {
     signup(userInput: {email: "organizer@example.com", password: "password"}, role: ORGANIZER) {
       access_token
     }
   }

   mutation {
     login(userInput: {email: "organizer@example.com", password: "password"}) {
       access_token
     }
   }

   mutation {
     createEvent(title: "Event Title", description: "Event Description") {
       success
     }
   }
   ```

This setup provides a robust foundation for role-based access control in your event management system. You can now add more roles and permissions as needed, ensuring each user has access to only the appropriate features and functionalities.

Let's extend our backend to include event management functionality. We'll implement the ability for organizers to create, edit, and delete events, and for users to view and search for events. We'll start by updating the Prisma schema and then proceed to the NestJS service and resolver layers.

### Update Prisma Schema for Events

Update `prisma/schema.prisma` to include the `Event` model:
```prisma
model Event {
  id          Int      @id @default(autoincrement())
  title       String
  description String
  date        DateTime
  time        String
  venue       String
  tickets     Ticket[]
  organizer   User     @relation(fields: [organizerId], references: [id])
  organizerId Int
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

model Ticket {
  id       Int    @id @default(autoincrement())
  type     String
  price    Float
  quantity Int
  event    Event  @relation(fields: [eventId], references: [id])
  eventId  Int
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  password  String
  role      Role     @default(ATTENDEE)
  events    Event[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

enum Role {
  ADMIN
  ORGANIZER
  ATTENDEE
}
```

Run the Prisma migration:
```bash
npx prisma migrate dev --name add-events
```

### Create Event Module in NestJS

1. **Create Event DTOs**

Create `dto/create-event.input.ts`:
```typescript
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateEventInput {
  @Field()
  title: string;

  @Field()
  description: string;

  @Field()
  date: Date;

  @Field()
  time: string;

  @Field()
  venue: string;

  @Field(() => [CreateTicketInput])
  tickets: CreateTicketInput[];
}
```

Create `dto/create-ticket.input.ts`:
```typescript
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateTicketInput {
  @Field()
  type: string;

  @Field()
  price: number;

  @Field()
  quantity: number;
}
```

Create `dto/update-event.input.ts`:
```typescript
import { InputType, Field, PartialType } from '@nestjs/graphql';
import { CreateEventInput } from './create-event.input';

@InputType()
export class UpdateEventInput extends PartialType(CreateEventInput) {
  @Field()
  id: number;
}
```

2. **Create Event Service**

Create `events.service.ts`:
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateEventInput } from './dto/create-event.input';
import { UpdateEventInput } from './dto/update-event.input';

@Injectable()
export class EventsService {
  constructor(private readonly prisma: PrismaService) {}

  async createEvent(createEventInput: CreateEventInput, organizerId: number) {
    const { tickets, ...eventData } = createEventInput;
    const event = await this.prisma.event.create({
      data: {
        ...eventData,
        organizer: { connect: { id: organizerId } },
        tickets: {
          create: tickets,
        },
      },
    });
    return event;
  }

  async updateEvent(updateEventInput: UpdateEventInput) {
    const { id, tickets, ...eventData } = updateEventInput;
    const event = await this.prisma.event.update({
      where: { id },
      data: {
        ...eventData,
        tickets: {
          deleteMany: { eventId: id },
          create: tickets,
        },
      },
    });
    return event;
  }

  async deleteEvent(id: number) {
    await this.prisma.event.delete({ where: { id } });
    return true;
  }

  async getEvent(id: number) {
    return this.prisma.event.findUnique({ where: { id } });
  }

  async getEvents() {
    return this.prisma.event.findMany();
  }

  async searchEvents(searchTerm: string) {
    return this.prisma.event.findMany({
      where: {
        OR: [
          { title: { contains: searchTerm, mode: 'insensitive' } },
          { description: { contains: searchTerm, mode: 'insensitive' } },
          { venue: { contains: searchTerm, mode: 'insensitive' } },
        ],
      },
    });
  }
}
```

3. **Create Event Resolver**

Create `events.resolver.ts`:
```typescript
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { EventsService } from './events.service';
import { CreateEventInput } from './dto/create-event.input';
import { UpdateEventInput } from './dto/update-event.input';
import { Event } from '@prisma/client';
import { UseGuards } from '@nestjs/common';
import { RolesGuard } from '../auth/roles.guard';
import { Roles } from '../auth/roles.decorator';
import { Role } from '@prisma/client';

@Resolver('Event')
export class EventsResolver {
  constructor(private readonly eventsService: EventsService) {}

  @Mutation(() => Event)
  @Roles(Role.ORGANIZER)
  @UseGuards(RolesGuard)
  async createEvent(
    @Args('createEventInput') createEventInput: CreateEventInput,
    @Args('organizerId') organizerId: number,
  ) {
    return this.eventsService.createEvent(createEventInput, organizerId);
  }

  @Mutation(() => Event)
  @Roles(Role.ORGANIZER)
  @UseGuards(RolesGuard)
  async updateEvent(@Args('updateEventInput') updateEventInput: UpdateEventInput) {
    return this.eventsService.updateEvent(updateEventInput);
  }

  @Mutation(() => Boolean)
  @Roles(Role.ORGANIZER)
  @UseGuards(RolesGuard)
  async deleteEvent(@Args('id') id: number) {
    return this.eventsService.deleteEvent(id);
  }

  @Query(() => Event)
  async event(@Args('id') id: number) {
    return this.eventsService.getEvent(id);
  }

  @Query(() => [Event])
  async events() {
    return this.eventsService.getEvents();
  }

  @Query(() => [Event])
  async searchEvents(@Args('searchTerm') searchTerm: string) {
    return this.eventsService.searchEvents(searchTerm);
  }
}
```

4. **Create Event Module**

Create `events.module.ts`:
```typescript
import { Module } from '@nestjs/common';
import { EventsService } from './events.service';
import { EventsResolver } from './events.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [EventsService, EventsResolver],
})
export class EventsModule {}
```

5. **Integrate Event Module in App Module**

Update `app.module.ts`:
```typescript
import { Module } from '@nestjs/common';
import { AuthModule } from './auth/auth.module';
import { PrismaModule } from './prisma/prisma.module';
import { GraphqlModule } from './graphql/graphql.module';
import { EventsModule } from './events/events.module';

@Module({
  imports: [
    AuthModule,
    PrismaModule,
    GraphqlModule,
    EventsModule,
  ],
})
export class AppModule {}
```

### Running the Backend

1. **Start the NestJS Server**
   ```bash
   npm run start:dev
   ```

2. **Test Event Management Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the event management queries and mutations:

   ```graphql
   mutation {
     createEvent(
       createEventInput: {
         title: "Sample Event"
         description: "This is a sample event."
         date: "2024-08-01T00:00:00.000Z"
         time: "18:00"
         venue: "Sample Venue"
         tickets: [
           { type: "General", price: 100.0, quantity: 100 }
           { type: "VIP", price: 200.0, quantity: 50 }
         ]
       }
       organizerId: 1
     ) {
       id
       title
       description
       date
       time
       venue
       tickets {
         type
         price
         quantity
       }
     }
   }

   mutation {
     updateEvent(
       updateEventInput: {
         id: 1
         title: "Updated Event Title"
         description: "Updated description."
         date: "2024-08-02T00:00:00.000Z"
         time: "19:00"
         venue: "Updated Venue"
         tickets: [
           { type: "General", price: 120.0, quantity: 100 }
           { type: "VIP", price: 250.0, quantity: 50 }
         ]
       }
     ) {
       id
       title
       description
       date
       time
       venue
       tickets {
         type
         price
         quantity
       }
     }
   }

   mutation {
     deleteEvent(id: 1)
   }

   query {
     event(id: 1) {
       id
       title
       description
       date
       time
       venue
       tickets {
         type
         price
         quantity


       }
     }
   }

   query {
     events {
       id
       title
       description
       date
       time
       venue
     }
   }

   query {
     searchEvents(searchTerm: "Sample") {
       id
       title
       description
       date
       time
       venue
     }
   }
   ```

This setup provides the necessary backend functionality for event management, allowing organizers to create, update, and delete events, and enabling users to view and search for events. You can further extend these functionalities as needed.

To add ticket management to our event management system, we'll extend our backend to include the functionality for creating tickets, purchasing tickets, and viewing purchased tickets. We'll update the Prisma schema to track ticket purchases, and then add the necessary service and resolver methods in NestJS.

### Update Prisma Schema for Ticket Purchases

Update `prisma/schema.prisma` to include the `TicketPurchase` model:
```prisma
model TicketPurchase {
  id       Int      @id @default(autoincrement())
  user     User     @relation(fields: [userId], references: [id])
  userId   Int
  ticket   Ticket   @relation(fields: [ticketId], references: [id])
  ticketId Int
  quantity Int
  totalPrice Float
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Ticket {
  id       Int    @id @default(autoincrement())
  type     String
  price    Float
  quantity Int
  event    Event  @relation(fields: [eventId], references: [id])
  eventId  Int
  purchases TicketPurchase[]
}

model Event {
  id          Int             @id @default(autoincrement())
  title       String
  description String
  date        DateTime
  time        String
  venue       String
  tickets     Ticket[]
  organizer   User            @relation(fields: [organizerId], references: [id])
  organizerId Int
  createdAt   DateTime        @default(now())
  updatedAt   DateTime        @updatedAt
}

model User {
  id            Int            @id @default(autoincrement())
  email         String         @unique
  password      String
  role          Role           @default(ATTENDEE)
  events        Event[]
  ticketPurchases TicketPurchase[]
  createdAt     DateTime       @default(now())
  updatedAt     DateTime       @updatedAt
}

enum Role {
  ADMIN
  ORGANIZER
  ATTENDEE
}
```

Run the Prisma migration:
```bash
npx prisma migrate dev --name add-ticket-purchases
```

### Create Ticket Management Service

Create `tickets.service.ts`:
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateTicketInput } from './dto/create-ticket.input';
import { PurchaseTicketInput } from './dto/purchase-ticket.input';

@Injectable()
export class TicketsService {
  constructor(private readonly prisma: PrismaService) {}

  async createTicket(createTicketInput: CreateTicketInput, eventId: number) {
    const ticket = await this.prisma.ticket.create({
      data: {
        ...createTicketInput,
        event: { connect: { id: eventId } },
      },
    });
    return ticket;
  }

  async purchaseTicket(purchaseTicketInput: PurchaseTicketInput, userId: number) {
    const { ticketId, quantity } = purchaseTicketInput;
    const ticket = await this.prisma.ticket.findUnique({ where: { id: ticketId } });

    if (!ticket || ticket.quantity < quantity) {
      throw new Error('Insufficient ticket quantity');
    }

    const totalPrice = ticket.price * quantity;

    const purchase = await this.prisma.ticketPurchase.create({
      data: {
        user: { connect: { id: userId } },
        ticket: { connect: { id: ticketId } },
        quantity,
        totalPrice,
      },
    });

    await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        quantity: ticket.quantity - quantity,
      },
    });

    return purchase;
  }

  async getUserTickets(userId: number) {
    return this.prisma.ticketPurchase.findMany({
      where: { userId },
      include: { ticket: true, event: true },
    });
  }
}
```

### Create Ticket Management Resolvers

Create `tickets.resolver.ts`:
```typescript
import { Resolver, Mutation, Args, Query } from '@nestjs/graphql';
import { TicketsService } from './tickets.service';
import { CreateTicketInput } from './dto/create-ticket.input';
import { PurchaseTicketInput } from './dto/purchase-ticket.input';
import { Ticket, TicketPurchase } from '@prisma/client';
import { UseGuards } from '@nestjs/common';
import { RolesGuard } from '../auth/roles.guard';
import { Roles } from '../auth/roles.decorator';
import { Role } from '@prisma/client';

@Resolver('Ticket')
export class TicketsResolver {
  constructor(private readonly ticketsService: TicketsService) {}

  @Mutation(() => Ticket)
  @Roles(Role.ORGANIZER)
  @UseGuards(RolesGuard)
  async createTicket(
    @Args('createTicketInput') createTicketInput: CreateTicketInput,
    @Args('eventId') eventId: number,
  ) {
    return this.ticketsService.createTicket(createTicketInput, eventId);
  }

  @Mutation(() => TicketPurchase)
  @Roles(Role.ATTENDEE)
  @UseGuards(RolesGuard)
  async purchaseTicket(
    @Args('purchaseTicketInput') purchaseTicketInput: PurchaseTicketInput,
    @Args('userId') userId: number,
  ) {
    return this.ticketsService.purchaseTicket(purchaseTicketInput, userId);
  }

  @Query(() => [TicketPurchase])
  @Roles(Role.ATTENDEE)
  @UseGuards(RolesGuard)
  async userTickets(@Args('userId') userId: number) {
    return this.ticketsService.getUserTickets(userId);
  }
}
```

### Create Ticket Management DTOs

Create `dto/create-ticket.input.ts`:
```typescript
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class CreateTicketInput {
  @Field()
  type: string;

  @Field()
  price: number;

  @Field()
  quantity: number;
}
```

Create `dto/purchase-ticket.input.ts`:
```typescript
import { InputType, Field } from '@nestjs/graphql';

@InputType()
export class PurchaseTicketInput {
  @Field()
  ticketId: number;

  @Field()
  quantity: number;
}
```

### Create Ticket Module

Create `tickets.module.ts`:
```typescript
import { Module } from '@nestjs/common';
import { TicketsService } from './tickets.service';
import { TicketsResolver } from './tickets.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [TicketsService, TicketsResolver],
})
export class TicketsModule {}
```

### Integrate Ticket Module in App Module

Update `app.module.ts`:
```typescript
import { Module } from '@nestjs/common';
import { AuthModule } from './auth/auth.module';
import { PrismaModule } from './prisma/prisma.module';
import { GraphqlModule } from './graphql/graphql.module';
import { EventsModule } from './events/events.module';
import { TicketsModule } from './tickets/tickets.module';

@Module({
  imports: [
    AuthModule,
    PrismaModule,
    GraphqlModule,
    EventsModule,
    TicketsModule,
  ],
})
export class AppModule {}
```

### Running the Backend

1. **Start the NestJS Server**
   ```bash
   npm run start:dev
   ```

2. **Test Ticket Management Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the ticket management queries and mutations:

   ```graphql
   mutation {
     createTicket(
       createTicketInput: {
         type: "General"
         price: 100.0
         quantity: 100
       }
       eventId: 1
     ) {
       id
       type
       price
       quantity
     }
   }

   mutation {
     purchaseTicket(
       purchaseTicketInput: {
         ticketId: 1
         quantity: 2
       }
       userId: 1
     ) {
       id
       quantity
       totalPrice
       ticket {
         type
         price
       }
     }
   }

   query {
     userTickets(userId: 1) {
       id
       quantity
       totalPrice
       ticket {
         type
         price
       }
       createdAt
     }
   }
   ```

This setup provides the necessary backend functionality for ticket management, allowing organizers to create tickets, attendees to purchase tickets, and users to view their purchased tickets. You can further extend these functionalities as needed.

To implement a notification system in the backend, we'll need to integrate both email notifications and in-app notifications. We'll use a service like SendGrid or Nodemailer for email notifications and a real-time mechanism like WebSockets for in-app notifications.

### Setting Up Email Notifications

1. **Install Nodemailer**

   ```bash
   npm install nodemailer
   ```

2. **Create Email Service**

   Create `email.service.ts`:
   ```typescript
   import { Injectable } from '@nestjs/common';
   import * as nodemailer from 'nodemailer';

   @Injectable()
   export class EmailService {
     private transporter;

     constructor() {
       this.transporter = nodemailer.createTransport({
         service: 'gmail',
         auth: {
           user: process.env.EMAIL_USER,
           pass: process.env.EMAIL_PASS,
         },
       });
     }

     async sendMail(to: string, subject: string, text: string) {
       const mailOptions = {
         from: process.env.EMAIL_USER,
         to,
         subject,
         text,
       };

       await this.transporter.sendMail(mailOptions);
     }
   }
   ```

3. **Update Environment Variables**

   Add the following to your `.env` file:
   ```
   EMAIL_USER=your-email@gmail.com
   EMAIL_PASS=your-email-password
   ```

4. **Integrate Email Service in Ticket Service**

   Update `tickets.service.ts` to send an email notification after purchasing a ticket:
   ```typescript
   import { Injectable } from '@nestjs/common';
   import { PrismaService } from '../prisma/prisma.service';
   import { CreateTicketInput } from './dto/create-ticket.input';
   import { PurchaseTicketInput } from './dto/purchase-ticket.input';
   import { EmailService } from '../email/email.service';

   @Injectable()
   export class TicketsService {
     constructor(
       private readonly prisma: PrismaService,
       private readonly emailService: EmailService,
     ) {}

     async createTicket(createTicketInput: CreateTicketInput, eventId: number) {
       const ticket = await this.prisma.ticket.create({
         data: {
           ...createTicketInput,
           event: { connect: { id: eventId } },
         },
       });
       return ticket;
     }

     async purchaseTicket(purchaseTicketInput: PurchaseTicketInput, userId: number) {
       const { ticketId, quantity } = purchaseTicketInput;
       const ticket = await this.prisma.ticket.findUnique({ where: { id: ticketId } });

       if (!ticket || ticket.quantity < quantity) {
         throw new Error('Insufficient ticket quantity');
       }

       const totalPrice = ticket.price * quantity;

       const purchase = await this.prisma.ticketPurchase.create({
         data: {
           user: { connect: { id: userId } },
           ticket: { connect: { id: ticketId } },
           quantity,
           totalPrice,
         },
       });

       await this.prisma.ticket.update({
         where: { id: ticketId },
         data: {
           quantity: ticket.quantity - quantity,
         },
       });

       const user = await this.prisma.user.findUnique({ where: { id: userId } });

       // Send email notification
       await this.emailService.sendMail(
         user.email,
         'Ticket Purchase Confirmation',
         `You have successfully purchased ${quantity} tickets for ${ticket.type} at ${ticket.event.title}. Total price: ${totalPrice}`,
       );

       return purchase;
     }

     async getUserTickets(userId: number) {
       return this.prisma.ticketPurchase.findMany({
         where: { userId },
         include: { ticket: true, event: true },
       });
     }
   }
   ```

5. **Create Email Module**

   Create `email.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { EmailService } from './email.service';

   @Module({
     providers: [EmailService],
     exports: [EmailService],
   })
   export class EmailModule {}
   ```

6. **Integrate Email Module in App Module**

   Update `app.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { AuthModule } from './auth/auth.module';
   import { PrismaModule } from './prisma/prisma.module';
   import { GraphqlModule } from './graphql/graphql.module';
   import { EventsModule } from './events/events.module';
   import { TicketsModule } from './tickets/tickets.module';
   import { EmailModule } from './email/email.module';

   @Module({
     imports: [
       AuthModule,
       PrismaModule,
       GraphqlModule,
       EventsModule,
       TicketsModule,
       EmailModule,
     ],
   })
   export class AppModule {}
   ```

### Setting Up In-App Notifications

1. **Install WebSockets**

   ```bash
   npm install @nestjs/websockets @nestjs/platform-socket.io
   ```

2. **Create Notification Gateway**

   Create `notification.gateway.ts`:
   ```typescript
   import {
     WebSocketGateway,
     WebSocketServer,
     SubscribeMessage,
     OnGatewayConnection,
     OnGatewayDisconnect,
   } from '@nestjs/websockets';
   import { Server, Socket } from 'socket.io';

   @WebSocketGateway()
   export class NotificationGateway implements OnGatewayConnection, OnGatewayDisconnect {
     @WebSocketServer() server: Server;

     async handleConnection(client: Socket) {
       console.log(`Client connected: ${client.id}`);
     }

     async handleDisconnect(client: Socket) {
       console.log(`Client disconnected: ${client.id}`);
     }

     @SubscribeMessage('message')
     async onMessage(client: Socket, message: string) {
       console.log(message);
     }

     async sendNotification(event: string, data: any) {
       this.server.emit(event, data);
     }
   }
   ```

3. **Integrate Notification Gateway in Ticket Service**

   Update `tickets.service.ts` to send an in-app notification after purchasing a ticket:
   ```typescript
   import { Injectable } from '@nestjs/common';
   import { PrismaService } from '../prisma/prisma.service';
   import { CreateTicketInput } from './dto/create-ticket.input';
   import { PurchaseTicketInput } from './dto/purchase-ticket.input';
   import { EmailService } from '../email/email.service';
   import { NotificationGateway } from '../notification/notification.gateway';

   @Injectable()
   export class TicketsService {
     constructor(
       private readonly prisma: PrismaService,
       private readonly emailService: EmailService,
       private readonly notificationGateway: NotificationGateway,
     ) {}

     async createTicket(createTicketInput: CreateTicketInput, eventId: number) {
       const ticket = await this.prisma.ticket.create({
         data: {
           ...createTicketInput,
           event: { connect: { id: eventId } },
         },
       });
       return ticket;
     }

     async purchaseTicket(purchaseTicketInput: PurchaseTicketInput, userId: number) {
       const { ticketId, quantity } = purchaseTicketInput;
       const ticket = await this.prisma.ticket.findUnique({ where: { id: ticketId } });

       if (!ticket || ticket.quantity < quantity) {
         throw new Error('Insufficient ticket quantity');
       }

       const totalPrice = ticket.price * quantity;

       const purchase = await this.prisma.ticketPurchase.create({
         data: {
           user: { connect: { id: userId } },
           ticket: { connect: { id: ticketId } },
           quantity,
           totalPrice,
         },
       });

       await this.prisma.ticket.update({
         where: { id: ticketId },
         data: {
           quantity: ticket.quantity - quantity,
         },
       });

       const user = await this.prisma.user.findUnique({ where: { id: userId } });

       // Send email notification
       await this.emailService.sendMail(
         user.email,
         'Ticket Purchase Confirmation',
         `You have successfully purchased ${quantity} tickets for ${ticket.type} at ${ticket.event.title}. Total price: ${totalPrice}`,
       );

       // Send in-app notification
       await this.notificationGateway.sendNotification('ticketPurchased', {
         userId,
         message: `You have successfully purchased ${quantity} tickets for ${ticket.type} at ${ticket.event.title}.`,
       });

       return purchase;
     }

     async getUserTickets(userId: number) {
       return this.prisma.ticketPurchase.findMany({
         where: { userId },
         include: { ticket: true, event: true },
       });
     }
   }
   ```

4. **Create Notification Module**

   Create `notification.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { NotificationGateway } from './notification.gateway';

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

5. **Integrate Notification Module in App Module**

   Update `app.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { AuthModule } from './auth/auth.module';
   import { PrismaModule } from './prisma/prisma.module';
   import { GraphqlModule } from './graphql/graphql.module';
   import { EventsModule } from './events/events.module';
   import { TicketsModule } from './tickets/tickets.module';
   import { EmailModule } from './email/email.module';
   import { NotificationModule } from './notification/notification.module';

   @Module({
     imports: [
       AuthModule,
       PrismaModule,
       GraphqlModule,
       EventsModule,
       TicketsModule,
       EmailModule,
       NotificationModule,
     ],
   })
   export class AppModule {}
   ```

### Running the Backend

1. **Start the NestJS Server**
  

 ```bash
   npm run start:dev
   ```

2. **Test Notification Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the ticket purchase mutation:

   ```graphql
   mutation {
     purchaseTicket(
       purchaseTicketInput: {
         ticketId: 1
         quantity: 2
       }
       userId: 1
     ) {
       id
       quantity
       totalPrice
       ticket {
         type
         price
       }
     }
   }
   ```

   Check the console output for WebSocket connection messages and email inbox for the notification email.

This setup provides the necessary backend functionality for both email and in-app notifications. You can further extend these functionalities as needed.

To integrate a payment gateway for ticket purchases, we'll use Stripe. Stripe provides robust APIs for handling payments, subscriptions, and more. We'll integrate Stripe into our NestJS backend.

### Setting Up Stripe

1. **Install Stripe SDK**

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

2. **Create Stripe Service**

   Create `stripe.service.ts`:
   ```typescript
   import { Injectable } from '@nestjs/common';
   import Stripe from 'stripe';

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

     constructor() {
       this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
         apiVersion: '2020-08-27',
       });
     }

     async createPaymentIntent(amount: number, currency: string) {
       return await this.stripe.paymentIntents.create({
         amount,
         currency,
       });
     }

     async confirmPaymentIntent(paymentIntentId: string) {
       return await this.stripe.paymentIntents.confirm(paymentIntentId);
     }
   }
   ```

3. **Update Environment Variables**

   Add the following to your `.env` file:
   ```
   STRIPE_SECRET_KEY=your-stripe-secret-key
   STRIPE_PUBLIC_KEY=your-stripe-public-key
   ```

4. **Create Payment DTOs**

   Create `dto/create-payment.dto.ts`:
   ```typescript
   export class CreatePaymentDto {
     amount: number;
     currency: string;
   }
   ```

   Create `dto/confirm-payment.dto.ts`:
   ```typescript
   export class ConfirmPaymentDto {
     paymentIntentId: string;
   }
   ```

5. **Create Payment Resolver**

   Create `payment.resolver.ts`:
   ```typescript
   import { Resolver, Mutation, Args } from '@nestjs/graphql';
   import { StripeService } from './stripe.service';
   import { CreatePaymentDto } from './dto/create-payment.dto';
   import { ConfirmPaymentDto } from './dto/confirm-payment.dto';

   @Resolver()
   export class PaymentResolver {
     constructor(private readonly stripeService: StripeService) {}

     @Mutation(() => String)
     async createPaymentIntent(@Args('createPaymentDto') createPaymentDto: CreatePaymentDto) {
       const paymentIntent = await this.stripeService.createPaymentIntent(
         createPaymentDto.amount,
         createPaymentDto.currency,
       );
       return paymentIntent.client_secret;
     }

     @Mutation(() => String)
     async confirmPaymentIntent(@Args('confirmPaymentDto') confirmPaymentDto: ConfirmPaymentDto) {
       const paymentIntent = await this.stripeService.confirmPaymentIntent(confirmPaymentDto.paymentIntentId);
       return paymentIntent.status;
     }
   }
   ```

6. **Create Payment Module**

   Create `payment.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { StripeService } from './stripe.service';
   import { PaymentResolver } from './payment.resolver';

   @Module({
     providers: [StripeService, PaymentResolver],
   })
   export class PaymentModule {}
   ```

7. **Integrate Payment Module in App Module**

   Update `app.module.ts`:
   ```typescript
   import { Module } from '@nestjs/common';
   import { AuthModule } from './auth/auth.module';
   import { PrismaModule } from './prisma/prisma.module';
   import { GraphqlModule } from './graphql/graphql.module';
   import { EventsModule } from './events/events.module';
   import { TicketsModule } from './tickets/tickets.module';
   import { EmailModule } from './email/email.module';
   import { NotificationModule } from './notification/notification.module';
   import { PaymentModule } from './payment/payment.module';

   @Module({
     imports: [
       AuthModule,
       PrismaModule,
       GraphqlModule,
       EventsModule,
       TicketsModule,
       EmailModule,
       NotificationModule,
       PaymentModule,
     ],
   })
   export class AppModule {}
   ```

### Integrate Payment Flow in Ticket Service

Update `tickets.service.ts` to create a payment intent before confirming the ticket purchase:

```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateTicketInput } from './dto/create-ticket.input';
import { PurchaseTicketInput } from './dto/purchase-ticket.input';
import { EmailService } from '../email/email.service';
import { NotificationGateway } from '../notification/notification.gateway';
import { StripeService } from '../payment/stripe.service';

@Injectable()
export class TicketsService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly emailService: EmailService,
    private readonly notificationGateway: NotificationGateway,
    private readonly stripeService: StripeService,
  ) {}

  async createTicket(createTicketInput: CreateTicketInput, eventId: number) {
    const ticket = await this.prisma.ticket.create({
      data: {
        ...createTicketInput,
        event: { connect: { id: eventId } },
      },
    });
    return ticket;
  }

  async purchaseTicket(purchaseTicketInput: PurchaseTicketInput, userId: number) {
    const { ticketId, quantity, paymentIntentId } = purchaseTicketInput;
    const ticket = await this.prisma.ticket.findUnique({ where: { id: ticketId } });

    if (!ticket || ticket.quantity < quantity) {
      throw new Error('Insufficient ticket quantity');
    }

    const totalPrice = ticket.price * quantity;

    const paymentIntent = await this.stripeService.confirmPaymentIntent(paymentIntentId);

    if (paymentIntent.status !== 'succeeded') {
      throw new Error('Payment failed');
    }

    const purchase = await this.prisma.ticketPurchase.create({
      data: {
        user: { connect: { id: userId } },
        ticket: { connect: { id: ticketId } },
        quantity,
        totalPrice,
      },
    });

    await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        quantity: ticket.quantity - quantity,
      },
    });

    const user = await this.prisma.user.findUnique({ where: { id: userId } });

    // Send email notification
    await this.emailService.sendMail(
      user.email,
      'Ticket Purchase Confirmation',
      `You have successfully purchased ${quantity} tickets for ${ticket.type} at ${ticket.event.title}. Total price: ${totalPrice}`,
    );

    // Send in-app notification
    await this.notificationGateway.sendNotification('ticketPurchased', {
      userId,
      message: `You have successfully purchased ${quantity} tickets for ${ticket.type} at ${ticket.event.title}.`,
    });

    return purchase;
  }

  async getUserTickets(userId: number) {
    return this.prisma.ticketPurchase.findMany({
      where: { userId },
      include: { ticket: true, event: true },
    });
  }
}
```

### Running the Backend

1. **Start the NestJS Server**

   ```bash
   npm run start:dev
   ```

2. **Test Payment Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the payment flow:

   1. Create a payment intent:
      ```graphql
      mutation {
        createPaymentIntent(createPaymentDto: { amount: 5000, currency: "usd" }) {
          client_secret
        }
      }
      ```

   2. Confirm the payment intent:
      ```graphql
      mutation {
        confirmPaymentIntent(confirmPaymentDto: { paymentIntentId: "pi_1JHYLR2eZvKYlo2C8kIfmQqN" }) {
          status
        }
      }
      ```

   3. Purchase a ticket:
      ```graphql
      mutation {
        purchaseTicket(
          purchaseTicketInput: {
            ticketId: 1
            quantity: 2
            paymentIntentId: "pi_1JHYLR2eZvKYlo2C8kIfmQqN"
          }
          userId: 1
        ) {
          id
          quantity
          totalPrice
          ticket {
            type
            price
          }
        }
      }
      ```

This setup provides the necessary backend functionality for integrating a payment gateway (Stripe) for ticket purchases. You can further extend these functionalities as needed.

To create a dashboard for different user roles (Admin, Organizer, and Attendee), we will need to build appropriate resolvers and services to fetch and aggregate the required data. We'll create separate services and resolvers for each type of dashboard.

### Admin Dashboard

**admin-dashboard.service.ts**
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class AdminDashboardService {
  constructor(private readonly prisma: PrismaService) {}

  async getSystemMetrics() {
    const userCount = await this.prisma.user.count();
    const eventCount = await this.prisma.event.count();
    const ticketSales = await this.prisma.ticketPurchase.count();
    return { userCount, eventCount, ticketSales };
  }

  async getUsers() {
    return this.prisma.user.findMany();
  }

  async getEvents() {
    return this.prisma.event.findMany();
  }
}
```

**admin-dashboard.resolver.ts**
```typescript
import { Resolver, Query } from '@nestjs/graphql';
import { AdminDashboardService } from './admin-dashboard.service';

@Resolver()
export class AdminDashboardResolver {
  constructor(private readonly adminDashboardService: AdminDashboardService) {}

  @Query(() => String)
  async getSystemMetrics() {
    return this.adminDashboardService.getSystemMetrics();
  }

  @Query(() => [User])
  async getUsers() {
    return this.adminDashboardService.getUsers();
  }

  @Query(() => [Event])
  async getEvents() {
    return this.adminDashboardService.getEvents();
  }
}
```

**admin-dashboard.module.ts**
```typescript
import { Module } from '@nestjs/common';
import { AdminDashboardService } from './admin-dashboard.service';
import { AdminDashboardResolver } from './admin-dashboard.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [AdminDashboardService, AdminDashboardResolver],
})
export class AdminDashboardModule {}
```

### Organizer Dashboard

**organizer-dashboard.service.ts**
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class OrganizerDashboardService {
  constructor(private readonly prisma: PrismaService) {}

  async getOrganizerEvents(organizerId: number) {
    return this.prisma.event.findMany({
      where: { organizerId },
      include: {
        tickets: true,
        purchases: true,
      },
    });
  }

  async getEventAttendees(eventId: number) {
    return this.prisma.ticketPurchase.findMany({
      where: { eventId },
      include: { user: true },
    });
  }
}
```

**organizer-dashboard.resolver.ts**
```typescript
import { Resolver, Query, Args, Int } from '@nestjs/graphql';
import { OrganizerDashboardService } from './organizer-dashboard.service';

@Resolver()
export class OrganizerDashboardResolver {
  constructor(private readonly organizerDashboardService: OrganizerDashboardService) {}

  @Query(() => [Event])
  async getOrganizerEvents(@Args('organizerId', { type: () => Int }) organizerId: number) {
    return this.organizerDashboardService.getOrganizerEvents(organizerId);
  }

  @Query(() => [TicketPurchase])
  async getEventAttendees(@Args('eventId', { type: () => Int }) eventId: number) {
    return this.organizerDashboardService.getEventAttendees(eventId);
  }
}
```

**organizer-dashboard.module.ts**
```typescript
import { Module } from '@nestjs/common';
import { OrganizerDashboardService } from './organizer-dashboard.service';
import { OrganizerDashboardResolver } from './organizer-dashboard.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [OrganizerDashboardService, OrganizerDashboardResolver],
})
export class OrganizerDashboardModule {}
```

### Attendee Dashboard

**attendee-dashboard.service.ts**
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class AttendeeDashboardService {
  constructor(private readonly prisma: PrismaService) {}

  async getUserEvents(userId: number) {
    return this.prisma.ticketPurchase.findMany({
      where: { userId },
      include: { event: true, ticket: true },
    });
  }
}
```

**attendee-dashboard.resolver.ts**
```typescript
import { Resolver, Query, Args, Int } from '@nestjs/graphql';
import { AttendeeDashboardService } from './attendee-dashboard.service';

@Resolver()
export class AttendeeDashboardResolver {
  constructor(private readonly attendeeDashboardService: AttendeeDashboardService) {}

  @Query(() => [TicketPurchase])
  async getUserEvents(@Args('userId', { type: () => Int }) userId: number) {
    return this.attendeeDashboardService.getUserEvents(userId);
  }
}
```

**attendee-dashboard.module.ts**
```typescript
import { Module } from '@nestjs/common';
import { AttendeeDashboardService } from './attendee-dashboard.service';
import { AttendeeDashboardResolver } from './attendee-dashboard.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [AttendeeDashboardService, AttendeeDashboardResolver],
})
export class AttendeeDashboardModule {}
```

### Integrate Dashboard Modules in App Module

Update `app.module.ts`:
```typescript
import { Module } from '@nestjs/common';
import { AuthModule } from './auth/auth.module';
import { PrismaModule } from './prisma/prisma.module';
import { GraphqlModule } from './graphql/graphql.module';
import { EventsModule } from './events/events.module';
import { TicketsModule } from './tickets/tickets.module';
import { EmailModule } from './email/email.module';
import { NotificationModule } from './notification/notification.module';
import { PaymentModule } from './payment/payment.module';
import { AdminDashboardModule } from './admin-dashboard/admin-dashboard.module';
import { OrganizerDashboardModule } from './organizer-dashboard/organizer-dashboard.module';
import { AttendeeDashboardModule } from './attendee-dashboard/attendee-dashboard.module';

@Module({
  imports: [
    AuthModule,
    PrismaModule,
    GraphqlModule,
    EventsModule,
    TicketsModule,
    EmailModule,
    NotificationModule,
    PaymentModule,
    AdminDashboardModule,
    OrganizerDashboardModule,
    AttendeeDashboardModule,
  ],
})
export class AppModule {}
```

### Running the Backend

1. **Start the NestJS Server**

   ```bash
   npm run start:dev
   ```

2. **Test Dashboard Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the dashboard queries:

   - **Admin Dashboard**:
     ```graphql
     query {
       getSystemMetrics {
         userCount
         eventCount
         ticketSales
       }

       getUsers {
         id
         email
         role
       }

       getEvents {
         id
         title
         date
         organizer {
           id
           name
         }
       }
     }
     ```

   - **Organizer Dashboard**:
     ```graphql
     query {
       getOrganizerEvents(organizerId: 1) {
         id
         title
         tickets {
           id
           type
           price
           quantity
         }
         purchases {
           id
           user {
             id
             email
           }
           quantity
           totalPrice
         }
       }

       getEventAttendees(eventId: 1) {
         id
         user {
           id
           email
         }
         quantity
         totalPrice
       }
     }
     ```

   - **Attendee Dashboard**:
     ```graphql
     query {
       getUserEvents(userId: 1) {
         id
         event {
           id
           title
           date
         }
         ticket {
           type
           price
         }
         quantity
         totalPrice
       }
     }
     ```

This setup provides the necessary backend functionality for the different dashboards (Admin, Organizer, and Attendee). You can further extend these functionalities as needed.

To implement analytics for event performance and user behavior, we'll create dedicated services and resolvers to handle these tasks. These services will fetch and process data from the database to provide insights.

### Event Analytics

**event-analytics.service.ts**
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class EventAnalyticsService {
  constructor(private readonly prisma: PrismaService) {}

  async getEventPerformance(eventId: number) {
    const ticketSales = await this.prisma.ticketPurchase.aggregate({
      _sum: { totalPrice: true },
      _count: { id: true },
      where: { eventId },
    });

    const attendeeDemographics = await this.prisma.user.findMany({
      where: {
        tickets: {
          some: { eventId },
        },
      },
      select: {
        age: true,
        gender: true,
        location: true,
      },
    });

    return { ticketSales, attendeeDemographics };
  }
}
```

**event-analytics.resolver.ts**
```typescript
import { Resolver, Query, Args, Int } from '@nestjs/graphql';
import { EventAnalyticsService } from './event-analytics.service';

@Resolver()
export class EventAnalyticsResolver {
  constructor(private readonly eventAnalyticsService: EventAnalyticsService) {}

  @Query(() => String)
  async getEventPerformance(@Args('eventId', { type: () => Int }) eventId: number) {
    return this.eventAnalyticsService.getEventPerformance(eventId);
  }
}
```

**event-analytics.module.ts**
```typescript
import { Module } from '@nestjs/common';
import { EventAnalyticsService } from './event-analytics.service';
import { EventAnalyticsResolver } from './event-analytics.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [EventAnalyticsService, EventAnalyticsResolver],
})
export class EventAnalyticsModule {}
```

### User Analytics

**user-analytics.service.ts**
```typescript
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class UserAnalyticsService {
  constructor(private readonly prisma: PrismaService) {}

  async getUserEngagement(userId: number) {
    const eventsAttended = await this.prisma.ticketPurchase.count({
      where: { userId },
    });

    const totalSpent = await this.prisma.ticketPurchase.aggregate({
      _sum: { totalPrice: true },
      where: { userId },
    });

    return { eventsAttended, totalSpent };
  }

  async getUserBehavior() {
    const activeUsers = await this.prisma.user.findMany({
      where: {
        tickets: {
          some: {},
        },
      },
      select: {
        id: true,
        email: true,
        tickets: {
          select: { eventId: true },
        },
      },
    });

    const userDemographics = await this.prisma.user.groupBy({
      by: ['age', 'gender', 'location'],
      _count: { id: true },
    });

    return { activeUsers, userDemographics };
  }
}
```

**user-analytics.resolver.ts**
```typescript
import { Resolver, Query, Args, Int } from '@nestjs/graphql';
import { UserAnalyticsService } from './user-analytics.service';

@Resolver()
export class UserAnalyticsResolver {
  constructor(private readonly userAnalyticsService: UserAnalyticsService) {}

  @Query(() => String)
  async getUserEngagement(@Args('userId', { type: () => Int }) userId: number) {
    return this.userAnalyticsService.getUserEngagement(userId);
  }

  @Query(() => String)
  async getUserBehavior() {
    return this.userAnalyticsService.getUserBehavior();
  }
}
```

**user-analytics.module.ts**
```typescript
import { Module } from '@nestjs/common';
import { UserAnalyticsService } from './user-analytics.service';
import { UserAnalyticsResolver } from './user-analytics.resolver';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
  imports: [PrismaModule],
  providers: [UserAnalyticsService, UserAnalyticsResolver],
})
export class UserAnalyticsModule {}
```

### Integrate Analytics Modules in App Module

Update `app.module.ts`:
```typescript
import { Module } from '@nestjs/common';
import { AuthModule } from './auth/auth.module';
import { PrismaModule } from './prisma/prisma.module';
import { GraphqlModule } from './graphql/graphql.module';
import { EventsModule } from './events/events.module';
import { TicketsModule } from './tickets/tickets.module';
import { EmailModule } from './email/email.module';
import { NotificationModule } from './notification/notification.module';
import { PaymentModule } from './payment/payment.module';
import { AdminDashboardModule } from './admin-dashboard/admin-dashboard.module';
import { OrganizerDashboardModule } from './organizer-dashboard/organizer-dashboard.module';
import { AttendeeDashboardModule } from './attendee-dashboard/attendee-dashboard.module';
import { EventAnalyticsModule } from './event-analytics/event-analytics.module';
import { UserAnalyticsModule } from './user-analytics/user-analytics.module';

@Module({
  imports: [
    AuthModule,
    PrismaModule,
    GraphqlModule,
    EventsModule,
    TicketsModule,
    EmailModule,
    NotificationModule,
    PaymentModule,
    AdminDashboardModule,
    OrganizerDashboardModule,
    AttendeeDashboardModule,
    EventAnalyticsModule,
    UserAnalyticsModule,
  ],
})
export class AppModule {}
```

### Running the Backend

1. **Start the NestJS Server**

   ```bash
   npm run start:dev
   ```

2. **Test Analytics Functionality**

   Access the GraphQL playground at `http://localhost:3000/graphql` and test the analytics queries:

   - **Event Analytics**:
     ```graphql
     query {
       getEventPerformance(eventId: 1) {
         ticketSales {
           _sum {
             totalPrice
           }
           _count {
             id
           }
         }
         attendeeDemographics {
           age
           gender
           location
         }
       }
     }
     ```

   - **User Analytics**:
     ```graphql
     query {
       getUserEngagement(userId: 1) {
         eventsAttended
         totalSpent {
           _sum {
             totalPrice
           }
         }
       }

       getUserBehavior {
         activeUsers {
           id
           email
           tickets {
             eventId
           }
         }
         userDemographics {
           age
           gender
           location
           _count {
             id
           }
         }
       }
     }
     ```

This setup provides the necessary backend functionality for event performance and user behavior analytics. You can further extend these functionalities as needed.

Disclaimer: This content is generated by AI.