first commit

This commit is contained in:
DerJesen
2025-11-29 12:26:58 +01:00
parent 2fae31f20f
commit fe5bbc1410
142 changed files with 19585 additions and 1 deletions

10
.gemini/settings.json Normal file
View File

@@ -0,0 +1,10 @@
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": [
"chrome-devtools-mcp@latest"
]
}
}
}

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
node_modules
# Keep environment variables out of version control
.env
/generated/prisma

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}

55
README.md Normal file
View File

@@ -0,0 +1,55 @@
# EventQR (NestJS + React)
A unified EventQR project with a NestJS backend and React frontend.
## Prerequisites
- Node.js
- PostgreSQL Database
## Setup
1. **Configure Database:**
Update `.env` with your PostgreSQL connection string.
```env
DATABASE_URL="postgresql://user:password@localhost:5432/eventqr"
JWT_SECRET="your-secret"
PASSWORD="your-login-password"
```
2. **Install Dependencies:**
```bash
npm install
```
3. **Setup Database:**
```bash
npx prisma migrate dev --name init
```
4. **Build Frontend:**
```bash
npm run build:client
```
5. **Start Server:**
```bash
npm run start:dev
```
The application will be available at `http://localhost:3000`.
API endpoints are at `http://localhost:3000/api`.
## Features
- **Auth:** JWT-based authentication with a simple password check (configured in `.env`).
- **Events:** Create and list events.
- **Tickets:** Generate tickets (Types: "Klassenbester", "1er Schüler", "Partyborner"). Scan and validate tickets.
- **Frontend:** React app served statically by NestJS.
## Development
- Backend: `src/`
- Frontend: `client/`
To work on the frontend, you can run `cd client && npm run dev` for hot-reloading, but you need to ensure it can proxy to the backend (configured in `vite.config.ts` to proxy `/api` to `http://localhost:3000`).

1
client/dist/assets/index-CB33grvy.css vendored Normal file

File diff suppressed because one or more lines are too long

30
client/dist/assets/index-DOfJxXvf.js vendored Normal file

File diff suppressed because one or more lines are too long

14
client/dist/index.html vendored Normal file
View File

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>event-qr-tool</title>
<script type="module" crossorigin src="/assets/index-DOfJxXvf.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CB33grvy.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

13
client/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>event-qr-tool</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

4245
client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

40
client/package.json Normal file
View File

@@ -0,0 +1,40 @@
{
"name": "event-qr-client",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@types/qrcode.react": "^1.0.5",
"@types/uuid": "^10.0.0",
"html5-qrcode": "^2.3.8",
"lucide-react": "^0.555.0",
"qrcode.react": "^4.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-router-dom": "^7.9.6",
"uuid": "^13.0.0"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/node": "^24.10.1",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"autoprefixer": "^10.4.22",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.17",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
"vite": "^7.2.4"
}
}

6
client/postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

30
client/src/App.tsx Normal file
View File

@@ -0,0 +1,30 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './pages/Home';
import { Generate } from './pages/Generate';
import { Scan } from './pages/Scan';
import { Login } from './pages/Login';
import { AuthProvider } from './context/AuthContext';
import { ProtectedRoute } from './components/ProtectedRoute';
function App() {
return (
<AuthProvider>
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoute />}>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/generate" element={<Generate />} />
<Route path="/scan" element={<Scan />} />
</Route>
</Route>
</Routes>
</Router>
</AuthProvider>
);
}
export default App;

View File

@@ -0,0 +1,72 @@
import React from 'react';
import { Link, useLocation, useNavigate, Outlet } from 'react-router-dom';
import { QrCode, Scan, Calendar, Mail, LogOut } from 'lucide-react';
import { useAuth } from '../context/AuthContext';
export const Layout: React.FC = () => {
const location = useLocation();
const navigate = useNavigate();
const { logout } = useAuth();
const isActive = (path: string) => location.pathname === path;
const handleLogout = () => {
logout();
navigate('/login');
};
return (
<div className="min-h-screen flex flex-col">
<nav className="glass-panel sticky top-0 z-50 border-x-0 border-t-0 rounded-none">
<div className="container py-4 flex justify-between items-center">
<Link to="/" className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-indigo-400 to-purple-400 flex items-center gap-2">
<QrCode className="text-indigo-400" />
EventQR
</Link>
<div className="flex gap-6 items-center">
<Link
to="/"
className={`flex items-center gap-2 hover:text-indigo-400 transition-colors ${isActive('/') ? 'text-indigo-400' : 'text-slate-400'}`}
>
<Calendar size={20} />
<span className="hidden sm:inline">Events</span>
</Link>
<Link
to="/generate"
className={`flex items-center gap-2 hover:text-indigo-400 transition-colors ${isActive('/generate') ? 'text-indigo-400' : 'text-slate-400'}`}
>
<Mail size={20} />
<span className="hidden sm:inline">Generate</span>
</Link>
<Link
to="/scan"
className={`flex items-center gap-2 hover:text-indigo-400 transition-colors ${isActive('/scan') ? 'text-indigo-400' : 'text-slate-400'}`}
>
<Scan size={20} />
<span className="hidden sm:inline">Scan</span>
</Link>
<div className="w-px h-6 bg-slate-700 mx-2"></div>
<button
onClick={handleLogout}
className="flex items-center gap-2 text-slate-400 hover:text-red-400 transition-colors"
title="Logout"
>
<LogOut size={20} />
</button>
</div>
</div>
</nav>
<main className="flex-1 container py-8 page-transition">
<Outlet />
</main>
<footer className="py-6 text-center text-slate-600 text-sm">
<p>© 2024 EventQR Tool. Built for seamless event management.</p>
</footer>
</div>
);
};

View File

@@ -0,0 +1,13 @@
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
export const ProtectedRoute: React.FC = () => {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
};

View File

@@ -0,0 +1,69 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
interface AuthContextType {
isAuthenticated: boolean;
login: (password: string) => Promise<boolean>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | null>(null);
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const token = sessionStorage.getItem('eventqr_token');
if (token) {
setIsAuthenticated(true);
}
setIsLoading(false);
}, []);
const login = async (password: string) => {
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password }),
});
if (response.ok) {
const data = await response.json();
if (data.accessToken) {
sessionStorage.setItem('eventqr_token', data.accessToken);
setIsAuthenticated(true);
return true;
}
}
return false;
} catch (error) {
console.error('Login failed:', error);
return false;
}
};
const logout = () => {
sessionStorage.removeItem('eventqr_token');
setIsAuthenticated(false);
fetch('/api/logout', { method: 'POST' });
};
if (isLoading) {
return null;
}
return (
<AuthContext.Provider value={{ isAuthenticated, login, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};

177
client/src/index.css Normal file
View File

@@ -0,0 +1,177 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--accent-primary: #6366f1;
--accent-secondary: #8b5cf6;
--accent-gradient: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
--success: #10b981;
--error: #ef4444;
--glass-bg: rgba(30, 41, 59, 0.7);
--glass-border: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background-color: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
line-height: 1.5;
}
#root {
min-height: 100vh;
display: flex;
flex-direction: column;
}
button {
cursor: pointer;
border: none;
outline: none;
font-family: inherit;
}
.glass-panel {
background: var(--glass-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--glass-border);
border-radius: 1rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.btn-primary {
background: var(--accent-gradient);
color: white;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-weight: 600;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary:hover {
opacity: 0.9;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
}
.btn-secondary {
background: var(--bg-secondary);
color: var(--text-primary);
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-weight: 600;
border: 1px solid var(--glass-border);
transition: all 0.2s ease;
}
.btn-secondary:hover {
background: #334155;
}
input,
select,
textarea {
background: var(--bg-secondary);
border: 1px solid var(--glass-border);
color: var(--text-primary);
padding: 0.75rem;
border-radius: 0.5rem;
width: 100%;
font-size: 1rem;
transition: border-color 0.2s;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: var(--accent-primary);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
width: 100%;
}
.page-transition {
/* animation: fadeIn 0.3s ease-in-out; */
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-primary);
}
::-webkit-scrollbar-thumb {
background: var(--bg-secondary);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #475569;
}
/* Scanner Overrides */
#reader {
border: none !important;
}
#reader video {
border-radius: 0.5rem;
object-fit: cover;
}
#reader__scan_region {
background: transparent !important;
}
#reader__dashboard_section_csr button {
background: var(--accent-gradient) !important;
color: white !important;
border: none !important;
padding: 0.5rem 1rem !important;
border-radius: 0.5rem !important;
font-weight: 600 !important;
margin-top: 1rem !important;
}
#reader__dashboard_section_swaplink {
color: var(--accent-primary) !important;
text-decoration: none !important;
margin-top: 0.5rem !important;
display: inline-block !important;
}

7
client/src/main.tsx Normal file
View File

@@ -0,0 +1,7 @@
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<App />
)

View File

@@ -0,0 +1,170 @@
import React, { useState } from 'react';
import { QRCodeSVG } from 'qrcode.react';
import { Save, RefreshCw, QrCode, Mail } from 'lucide-react';
import { saveTicket, resendTicketEmail } from '../utils/storage';
import type { Ticket } from '../types';
export const Generate: React.FC = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
type: 'Klassenbester' as Ticket['ticketType']
});
const [generatedTicket, setGeneratedTicket] = useState<Ticket | null>(null);
const [isSaving, setIsSaving] = useState(false);
const [resendStatus, setResendStatus] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSaving(true);
try {
const ticketData = {
eventId: 'default-event', // For now, single event
attendeeName: formData.name,
attendeeEmail: formData.email,
ticketType: formData.type,
};
const newTicket = await saveTicket(ticketData);
setGeneratedTicket(newTicket);
setResendStatus('idle'); // Reset resend status for new ticket
} catch (error) {
console.error(error);
alert('Failed to generate ticket. Please try again.');
} finally {
setIsSaving(false);
}
};
const handleResendEmail = async () => {
if (!generatedTicket) return;
setResendStatus('sending');
try {
await resendTicketEmail(generatedTicket.id);
setResendStatus('sent');
setTimeout(() => setResendStatus('idle'), 3000); // Reset after 3 seconds
} catch (error) {
console.error(error);
setResendStatus('error');
}
};
const reset = () => {
setGeneratedTicket(null);
setFormData({ name: '', email: '', type: 'Klassenbester' });
setResendStatus('idle');
};
return (
<div className="max-w-4xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold mb-2">Generate Ticket</h1>
<p className="text-slate-400">Create a new QR code ticket for an attendee.</p>
</div>
<form onSubmit={handleSubmit} className="glass-panel p-6 space-y-4">
<div>
<label className="block text-sm font-medium mb-2 text-slate-300">Attendee Name</label>
<input
required
type="text"
value={formData.name}
onChange={e => setFormData({ ...formData, name: e.target.value })}
placeholder="John Doe"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2 text-slate-300">Email Address</label>
<input
required
type="email"
value={formData.email}
onChange={e => setFormData({ ...formData, email: e.target.value })}
placeholder="john@example.com"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2 text-slate-300">Ticket Type</label>
<select
value={formData.type}
onChange={e => setFormData({ ...formData, type: e.target.value as any })}
>
<option value="Klassenbester">Klassenbester</option>
<option value="1er Schüler">1er Schüler</option>
<option value="Partyborner">Partyborner</option>
</select>
</div>
<button type="submit" className="btn-primary w-full justify-center mt-4" disabled={isSaving}>
{isSaving ? 'Generating...' : (
<>
<Save size={18} />
Generate Ticket
</>
)}
</button>
</form>
</div>
<div className="flex flex-col items-center justify-center">
{generatedTicket ? (
<div className="glass-panel p-8 text-center w-full max-w-sm animate-in fade-in zoom-in duration-300">
<div className="bg-green-500/10 text-green-400 p-3 rounded-lg mb-6 text-sm font-medium">
Ticket generated successfully!
</div>
<div className="bg-white p-4 rounded-lg inline-block mb-6">
<QRCodeSVG
value={JSON.stringify({ id: generatedTicket.id, type: generatedTicket.ticketType })}
size={200}
level="H"
/>
</div>
<h3 className="text-xl font-bold mb-1">{generatedTicket.attendeeName}</h3>
<p className="text-slate-400 text-sm mb-6">{generatedTicket.ticketType} Ticket</p>
<div className="space-y-3">
<button
onClick={handleResendEmail}
disabled={resendStatus === 'sending' || resendStatus === 'sent'}
className={`w-full justify-center flex items-center gap-2 py-2 rounded-lg transition-colors font-medium ${
resendStatus === 'sent'
? 'bg-green-500/20 text-green-400 cursor-default'
: 'bg-slate-700 hover:bg-slate-600 text-white'
}`}
>
{resendStatus === 'sending' ? (
'Sending...'
) : resendStatus === 'sent' ? (
'Email Sent!'
) : (
<>
<Mail size={18} />
Resend Email
</>
)}
</button>
<button
onClick={reset}
className="btn-secondary w-full justify-center"
>
<RefreshCw size={18} />
Create Another
</button>
</div>
</div>
) : (
<div className="text-center text-slate-500 p-12 border-2 border-dashed border-slate-700 rounded-xl">
<QrCode size={48} className="mx-auto mb-4 opacity-50" />
<p>Fill out the form to generate a ticket preview here.</p>
</div>
)}
</div>
</div>
);
};

142
client/src/pages/Home.tsx Normal file
View File

@@ -0,0 +1,142 @@
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { Plus, Users, QrCode, Trash2 } from 'lucide-react';
import { getTickets, deleteTicket } from '../utils/storage';
import type { Ticket } from '../types';
export const Home: React.FC = () => {
const [tickets, setTickets] = useState<Ticket[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchTickets = async () => {
try {
setLoading(true);
const fetchedTickets = await getTickets('default-event'); // For now, single event
setTickets(fetchedTickets);
} catch (err) {
setError('Failed to load tickets.');
console.error(err);
} finally {
setLoading(false);
}
};
fetchTickets();
}, []);
const handleDelete = async (id: string) => {
if (window.confirm('Are you sure you want to delete this ticket?')) {
try {
await deleteTicket(id);
setTickets(tickets.filter(t => t.id !== id));
} catch (err) {
alert('Failed to delete ticket.');
console.error(err);
}
}
};
return (
<div className="space-y-8">
<header className="flex justify-between items-end">
<div>
<h1 className="text-4xl font-bold mb-2">Dashboard</h1>
<p className="text-slate-400">Manage your events and attendees</p>
</div>
<Link to="/generate" className="btn-primary">
<Plus size={20} />
New Ticket
</Link>
</header>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="glass-panel p-6">
<div className="flex items-center gap-4 mb-4">
<div className="p-3 bg-indigo-500/20 rounded-lg text-indigo-400">
<Users size={24} />
</div>
<div>
<p className="text-sm text-slate-400">Total Attendees</p>
<p className="text-2xl font-bold">{tickets.length}</p>
</div>
</div>
</div>
<div className="glass-panel p-6">
<div className="flex items-center gap-4 mb-4">
<div className="p-3 bg-purple-500/20 rounded-lg text-purple-400">
<QrCode size={24} />
</div>
<div>
<p className="text-sm text-slate-400">Scanned Tickets</p>
<p className="text-2xl font-bold">{tickets.filter(t => t.status === 'used').length}</p>
</div>
</div>
</div>
</div>
<div className="glass-panel p-6">
<h2 className="text-xl font-bold mb-4">Recent Tickets</h2>
{loading ? (
<div className="text-center py-8 text-slate-500">
Loading tickets...
</div>
) : error ? (
<div className="text-center py-8 text-red-500">
{error}
</div>
) : tickets.length === 0 ? (
<div className="text-center py-8 text-slate-500">
No tickets generated yet.
</div>
) : (
<div className="overflow-x-auto">
<table className="w-full text-left border-collapse">
<thead>
<tr className="text-slate-400 border-b border-slate-700">
<th className="p-4">Name</th>
<th className="p-4">Email</th>
<th className="p-4">Type</th>
<th className="p-4">Status</th>
<th className="p-4 text-right">Actions</th>
</tr>
</thead>
<tbody>
{tickets.slice().reverse().map(ticket => (
<tr key={ticket.id} className="border-b border-slate-800 hover:bg-slate-800/50">
<td className="p-4 font-medium">{ticket.attendeeName}</td>
<td className="p-4 text-slate-400">{ticket.attendeeEmail}</td>
<td className="p-4">
<span className={`px-2 py-1 rounded-full text-xs ${ticket.ticketType === 'Partyborner' ? 'bg-amber-500/20 text-amber-400' : 'bg-blue-500/20 text-blue-400'
}`}>
{ticket.ticketType}
</span>
</td>
<td className="p-4">
<span className={`px-2 py-1 rounded-full text-xs ${ticket.status === 'valid' ? 'bg-green-500/20 text-green-400' : 'bg-slate-500/20 text-slate-400'
}`}>
{ticket.status}
</span>
</td>
<td className="p-4 text-right">
<button
onClick={() => handleDelete(ticket.id)}
className="text-slate-500 hover:text-red-400 transition-colors p-2"
title="Delete Ticket"
>
<Trash2 size={18} />
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</div>
);
};

View File

@@ -0,0 +1,65 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { Lock } from 'lucide-react';
export const Login: React.FC = () => {
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const { login } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setIsSubmitting(true);
try {
const success = await login(password);
if (success) {
navigate('/');
} else {
setError('Invalid password');
}
} catch {
setError('An error occurred. Please try again.');
} finally {
setIsSubmitting(false);
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-slate-900 p-4">
<div className="glass-panel p-8 w-full max-w-md">
<div className="text-center mb-8">
<div className="inline-block p-4 rounded-full bg-indigo-500/20 text-indigo-400 mb-4">
<Lock size={32} />
</div>
<h1 className="text-2xl font-bold">EventQR Login</h1>
<p className="text-slate-400">Please enter password to continue</p>
</div>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter password"
className="w-full bg-slate-800 border-slate-700 focus:border-indigo-500"
autoFocus
/>
</div>
{error && (
<p className="text-red-400 text-sm text-center">{error}</p>
)}
<button type="submit" className="btn-primary w-full justify-center" disabled={isSubmitting}>
{isSubmitting ? 'Logging in...' : 'Login'}
</button>
</form>
</div>
</div>
);
};

128
client/src/pages/Scan.tsx Normal file
View File

@@ -0,0 +1,128 @@
import React, { useEffect, useState } from 'react';
import { Html5QrcodeScanner } from 'html5-qrcode';
import { CheckCircle, XCircle, RefreshCw } from 'lucide-react';
import { getTickets, updateTicketStatus } from '../utils/storage';
import type { Ticket } from '../types';
export const Scan: React.FC = () => {
const [scanResult, setScanResult] = useState<{
success: boolean;
message: string;
ticket?: Ticket;
} | null>(null);
useEffect(() => {
// Prevent scanner from initializing if we already have a result
if (scanResult) return;
const scanner = new Html5QrcodeScanner(
"reader",
{ fps: 10, qrbox: { width: 250, height: 250 } },
/* verbose= */ false
);
scanner.render(
async (decodedText) => {
try {
scanner.clear();
const data = JSON.parse(decodedText);
const tickets = await getTickets('default-event'); // Hardcoded event
const ticket = tickets.find(t => t.id === data.id);
if (ticket) {
if (ticket.status === 'valid') {
const updatedTicket = await updateTicketStatus(ticket.id, 'used');
setScanResult({
success: true,
message: 'Ticket Valid! Access Granted.',
ticket: updatedTicket
});
} else {
setScanResult({
success: false,
message: 'Ticket already used!',
ticket
});
}
} else {
setScanResult({
success: false,
message: 'Invalid Ticket ID',
});
}
} catch (e) {
console.error(e);
setScanResult({
success: false,
message: 'Scan Error: Invalid QR code.',
});
}
},
() => {
// console.warn(error);
}
);
return () => {
scanner.clear().catch(error => {
console.error("Failed to clear html5-qrcode scanner. ", error);
});
};
}, [scanResult]);
const resetScanner = () => {
setScanResult(null);
};
return (
<div className="max-w-2xl mx-auto">
<div className="text-center mb-8">
<h1 className="text-3xl font-bold mb-2">Scan Tickets</h1>
<p className="text-slate-400">Use your camera to verify attendee tickets.</p>
</div>
<div className="glass-panel p-6 overflow-hidden">
{!scanResult ? (
<div className="relative">
<div id="reader" className="w-full rounded-lg overflow-hidden"></div>
<p className="text-center text-sm text-slate-500 mt-4">
Point camera at the QR code
</p>
</div>
) : (
<div className="text-center py-8 animate-in fade-in zoom-in duration-300">
{scanResult.success ? (
<div className="text-green-500 mb-4 flex justify-center">
<CheckCircle size={64} />
</div>
) : (
<div className="text-red-500 mb-4 flex justify-center">
<XCircle size={64} />
</div>
)}
<h2 className="text-2xl font-bold mb-2">
{scanResult.message}
</h2>
{scanResult.ticket && (
<div className="bg-slate-800/50 p-4 rounded-lg inline-block text-left mt-4 mb-6">
<p className="text-slate-400 text-sm">Attendee</p>
<p className="font-medium text-lg">{scanResult.ticket.attendeeName}</p>
<p className="text-slate-400 text-sm mt-2">Type</p>
<p className="font-medium text-lg">{scanResult.ticket.ticketType}</p>
</div>
)}
<div>
<button onClick={resetScanner} className="btn-primary">
<RefreshCw size={18} />
Scan Next
</button>
</div>
</div>
)}
</div>
</div>
);
};

16
client/src/types/index.ts Normal file
View File

@@ -0,0 +1,16 @@
export interface Event {
id: string;
name: string;
date: string;
location: string;
}
export interface Ticket {
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: 'Klassenbester' | '1er Schüler' | 'Partyborner';
status: 'valid' | 'used';
createdAt: string;
}

View File

@@ -0,0 +1,69 @@
import type { Event, Ticket } from '../types';
const API_URL = '/api';
const getHeaders = () => {
const token = sessionStorage.getItem('eventqr_token');
return {
'Content-Type': 'application/json',
...(token ? { 'Authorization': `Bearer ${token}` } : {}),
};
};
export const getEvents = async (): Promise<Event[]> => {
const response = await fetch(`${API_URL}/events`, { headers: getHeaders() });
if (!response.ok) throw new Error('Failed to fetch events');
return response.json();
};
export const saveEvent = async (event: Omit<Event, 'id'>): Promise<Event> => {
const response = await fetch(`${API_URL}/events`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(event),
});
if (!response.ok) throw new Error('Failed to save event');
return response.json();
};
export const getTickets = async (eventId: string): Promise<Ticket[]> => {
const response = await fetch(`${API_URL}/tickets?eventId=${eventId}`, { headers: getHeaders() });
if (!response.ok) throw new Error('Failed to fetch tickets');
return response.json();
};
export const saveTicket = async (ticket: Omit<Ticket, 'id' | 'status' | 'createdAt'>): Promise<Ticket> => {
const response = await fetch(`${API_URL}/tickets`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(ticket),
});
if (!response.ok) throw new Error('Failed to save ticket');
return response.json();
};
export const resendTicketEmail = async (ticketId: string): Promise<void> => {
const response = await fetch(`${API_URL}/tickets/${ticketId}/resend`, {
method: 'POST',
headers: getHeaders(),
});
if (!response.ok) throw new Error('Failed to resend ticket email');
};
export const updateTicketStatus = async (ticketId: string, status: 'valid' | 'used'): Promise<Ticket> => {
const response = await fetch(`${API_URL}/tickets/${ticketId}/status`, {
method: 'PUT',
headers: getHeaders(),
body: JSON.stringify({ status }),
});
if (!response.ok) throw new Error('Failed to update ticket status');
return response.json();
};
export const deleteTicket = async (ticketId: string): Promise<void> => {
const response = await fetch(`${API_URL}/tickets/${ticketId}`, {
method: 'DELETE',
headers: getHeaders(),
});
if (!response.ok) throw new Error('Failed to delete ticket');
};

11
client/tailwind.config.js Normal file
View File

@@ -0,0 +1,11 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}

28
client/tsconfig.app.json Normal file
View File

@@ -0,0 +1,28 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"types": ["vite/client"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

7
client/tsconfig.json Normal file
View File

@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

26
client/tsconfig.node.json Normal file
View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

15
client/vite.config.ts Normal file
View File

@@ -0,0 +1,15 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
}
}
}
})

6
dist/app.controller.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
import { AppService } from './app.service';
export declare class AppController {
private readonly appService;
constructor(appService: AppService);
getHello(): string;
}

34
dist/app.controller.js vendored Normal file
View File

@@ -0,0 +1,34 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppController = void 0;
const common_1 = require("@nestjs/common");
const app_service_1 = require("./app.service");
let AppController = class AppController {
constructor(appService) {
this.appService = appService;
}
getHello() {
return this.appService.getHello();
}
};
exports.AppController = AppController;
__decorate([
(0, common_1.Get)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", String)
], AppController.prototype, "getHello", null);
exports.AppController = AppController = __decorate([
(0, common_1.Controller)(),
__metadata("design:paramtypes", [app_service_1.AppService])
], AppController);
//# sourceMappingURL=app.controller.js.map

1
dist/app.controller.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,+CAA2C;AAGpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAGvD,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF,CAAA;AAPY,sCAAa;AAIxB;IADC,IAAA,YAAG,GAAE;;;;6CAGL;wBANU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE8B,wBAAU;GADxC,aAAa,CAOzB"}

2
dist/app.module.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class AppModule {
}

41
dist/app.module.js vendored Normal file
View File

@@ -0,0 +1,41 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppModule = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const serve_static_1 = require("@nestjs/serve-static");
const path_1 = require("path");
const app_controller_1 = require("./app.controller");
const app_service_1 = require("./app.service");
const prisma_module_1 = require("./prisma/prisma.module");
const events_module_1 = require("./events/events.module");
const tickets_module_1 = require("./tickets/tickets.module");
const auth_module_1 = require("./auth/auth.module");
const mail_module_1 = require("./mail/mail.module");
let AppModule = class AppModule {
};
exports.AppModule = AppModule;
exports.AppModule = AppModule = __decorate([
(0, common_1.Module)({
imports: [
config_1.ConfigModule.forRoot({ isGlobal: true }),
serve_static_1.ServeStaticModule.forRoot({
rootPath: (0, path_1.join)(__dirname, '..', 'client', 'dist')
}),
prisma_module_1.PrismaModule,
events_module_1.EventsModule,
tickets_module_1.TicketsModule,
auth_module_1.AuthModule,
mail_module_1.MailModule,
],
controllers: [app_controller_1.AppController],
providers: [app_service_1.AppService],
})
], AppModule);
//# sourceMappingURL=app.module.js.map

1
dist/app.module.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAC9C,uDAAyD;AACzD,+BAA4B;AAC5B,qDAAiD;AACjD,+CAA2C;AAC3C,0DAAsD;AACtD,0DAAsD;AACtD,6DAAyD;AACzD,oDAAgD;AAChD,oDAAgD;AAiBzC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IAfrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACxC,gCAAiB,CAAC,OAAO,CAAC;gBACxB,QAAQ,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;aAClD,CAAC;YACF,4BAAY;YACZ,4BAAY;YACZ,8BAAa;YACb,wBAAU;YACV,wBAAU;SACX;QACD,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,CAAC;KACxB,CAAC;GACW,SAAS,CAAG"}

3
dist/app.service.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
export declare class AppService {
getHello(): string;
}

20
dist/app.service.js vendored Normal file
View File

@@ -0,0 +1,20 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppService = void 0;
const common_1 = require("@nestjs/common");
let AppService = class AppService {
getHello() {
return 'Hello World!';
}
};
exports.AppService = AppService;
exports.AppService = AppService = __decorate([
(0, common_1.Injectable)()
], AppService);
//# sourceMappingURL=app.service.js.map

1
dist/app.service.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"app.service.js","sourceRoot":"","sources":["../src/app.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAGrC,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,QAAQ;QACN,OAAO,cAAc,CAAC;IACxB,CAAC;CACF,CAAA;AAJY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;GACA,UAAU,CAItB"}

18
dist/assets/atiw-out-logo.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.4 KiB

13
dist/auth/auth.controller.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import { AuthService } from './auth.service';
export declare class AuthController {
private readonly authService;
constructor(authService: AuthService);
login(body: {
password: string;
}): Promise<{
accessToken: string;
}>;
logout(): Promise<{
success: boolean;
}>;
}

49
dist/auth/auth.controller.js vendored Normal file
View File

@@ -0,0 +1,49 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthController = void 0;
const common_1 = require("@nestjs/common");
const auth_service_1 = require("./auth.service");
let AuthController = class AuthController {
constructor(authService) {
this.authService = authService;
}
async login(body) {
return this.authService.login(body.password);
}
async logout() {
return { success: true };
}
};
exports.AuthController = AuthController;
__decorate([
(0, common_1.Post)('login'),
(0, common_1.HttpCode)(common_1.HttpStatus.OK),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], AuthController.prototype, "login", null);
__decorate([
(0, common_1.Post)('logout'),
(0, common_1.HttpCode)(common_1.HttpStatus.OK),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], AuthController.prototype, "logout", null);
exports.AuthController = AuthController = __decorate([
(0, common_1.Controller)(),
__metadata("design:paramtypes", [auth_service_1.AuthService])
], AuthController);
//# sourceMappingURL=auth.controller.js.map

1
dist/auth/auth.controller.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA8E;AAC9E,iDAA6C;AAGtC,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,YAA6B,WAAwB;QAAxB,gBAAW,GAAX,WAAW,CAAa;IAAG,CAAC;IAInD,AAAN,KAAK,CAAC,KAAK,CAAS,IAA0B;QAC5C,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAIK,AAAN,KAAK,CAAC,MAAM;QACV,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AAdY,wCAAc;AAKnB;IAFL,IAAA,aAAI,EAAC,OAAO,CAAC;IACb,IAAA,iBAAQ,EAAC,mBAAU,CAAC,EAAE,CAAC;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;;;2CAElB;AAIK;IAFL,IAAA,aAAI,EAAC,QAAQ,CAAC;IACd,IAAA,iBAAQ,EAAC,mBAAU,CAAC,EAAE,CAAC;;;;4CAGvB;yBAbU,cAAc;IAD1B,IAAA,mBAAU,GAAE;qCAE+B,0BAAW;GAD1C,cAAc,CAc1B"}

2
dist/auth/auth.module.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class AuthModule {
}

38
dist/auth/auth.module.js vendored Normal file
View File

@@ -0,0 +1,38 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthModule = void 0;
const common_1 = require("@nestjs/common");
const auth_service_1 = require("./auth.service");
const auth_controller_1 = require("./auth.controller");
const jwt_1 = require("@nestjs/jwt");
const config_1 = require("@nestjs/config");
const passport_1 = require("@nestjs/passport");
const jwt_strategy_1 = require("./jwt.strategy");
let AuthModule = class AuthModule {
};
exports.AuthModule = AuthModule;
exports.AuthModule = AuthModule = __decorate([
(0, common_1.Module)({
imports: [
config_1.ConfigModule,
passport_1.PassportModule,
jwt_1.JwtModule.registerAsync({
imports: [config_1.ConfigModule],
useFactory: async (configService) => ({
secret: configService.get('JWT_SECRET') || 'secret',
signOptions: { expiresIn: '1d' },
}),
inject: [config_1.ConfigService],
}),
],
controllers: [auth_controller_1.AuthController],
providers: [auth_service_1.AuthService, jwt_strategy_1.JwtStrategy],
})
], AuthModule);
//# sourceMappingURL=auth.module.js.map

1
dist/auth/auth.module.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,iDAA6C;AAC7C,uDAAmD;AACnD,qCAAwC;AACxC,2CAA6D;AAC7D,+CAAkD;AAClD,iDAA6C;AAkBtC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAhBtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY;YACZ,yBAAc;YACd,eAAS,CAAC,aAAa,CAAC;gBACtB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAAE,EAAE,CAAC,CAAC;oBACnD,MAAM,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC,IAAI,QAAQ;oBAC3D,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;iBACjC,CAAC;gBACF,MAAM,EAAE,CAAC,sBAAa,CAAC;aACxB,CAAC;SACH;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,EAAE,0BAAW,CAAC;KACtC,CAAC;GACW,UAAU,CAAG"}

10
dist/auth/auth.service.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
export declare class AuthService {
private jwtService;
private configService;
constructor(jwtService: JwtService, configService: ConfigService);
login(password: string): Promise<{
accessToken: string;
}>;
}

38
dist/auth/auth.service.js vendored Normal file
View File

@@ -0,0 +1,38 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthService = void 0;
const common_1 = require("@nestjs/common");
const jwt_1 = require("@nestjs/jwt");
const config_1 = require("@nestjs/config");
let AuthService = class AuthService {
constructor(jwtService, configService) {
this.jwtService = jwtService;
this.configService = configService;
}
async login(password) {
const envPassword = this.configService.get('PASSWORD');
if (password !== envPassword) {
throw new common_1.UnauthorizedException('Incorrect password');
}
const payload = { username: 'admin', sub: 'admin' };
return {
accessToken: this.jwtService.sign(payload),
};
}
};
exports.AuthService = AuthService;
exports.AuthService = AuthService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [jwt_1.JwtService,
config_1.ConfigService])
], AuthService);
//# sourceMappingURL=auth.service.js.map

1
dist/auth/auth.service.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../src/auth/auth.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAmE;AACnE,qCAAyC;AACzC,2CAA+C;AAGxC,IAAM,WAAW,GAAjB,MAAM,WAAW;IACtB,YACU,UAAsB,EACtB,aAA4B;QAD5B,eAAU,GAAV,UAAU,CAAY;QACtB,kBAAa,GAAb,aAAa,CAAe;IACnC,CAAC;IAEJ,KAAK,CAAC,KAAK,CAAC,QAAgB;QAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,UAAU,CAAC,CAAC;QAC/D,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,8BAAqB,CAAC,oBAAoB,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,OAAO,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;QACpD,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;SAC3C,CAAC;IACJ,CAAC;CACF,CAAA;AAhBY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;qCAGW,gBAAU;QACP,sBAAa;GAH3B,WAAW,CAgBvB"}

13
dist/auth/jwt.strategy.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import { Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
declare const JwtStrategy_base: new (...args: [opt: import("passport-jwt").StrategyOptionsWithRequest] | [opt: import("passport-jwt").StrategyOptionsWithoutRequest]) => Strategy & {
validate(...args: any[]): unknown;
};
export declare class JwtStrategy extends JwtStrategy_base {
constructor(configService: ConfigService);
validate(payload: any): Promise<{
userId: any;
username: any;
}>;
}
export {};

34
dist/auth/jwt.strategy.js vendored Normal file
View File

@@ -0,0 +1,34 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JwtStrategy = void 0;
const passport_jwt_1 = require("passport-jwt");
const passport_1 = require("@nestjs/passport");
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(passport_jwt_1.Strategy) {
constructor(configService) {
super({
jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get('JWT_SECRET') || 'secret',
});
}
async validate(payload) {
return { userId: payload.sub, username: payload.username };
}
};
exports.JwtStrategy = JwtStrategy;
exports.JwtStrategy = JwtStrategy = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService])
], JwtStrategy);
//# sourceMappingURL=jwt.strategy.js.map

1
dist/auth/jwt.strategy.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../src/auth/jwt.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,+CAAoD;AACpD,+CAAoD;AACpD,2CAA4C;AAC5C,2CAA+C;AAGxC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,IAAA,2BAAgB,EAAC,uBAAQ,CAAC;IACzD,YAAY,aAA4B;QACtC,KAAK,CAAC;YACJ,cAAc,EAAE,yBAAU,CAAC,2BAA2B,EAAE;YACxD,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC,IAAI,QAAQ;SACjE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAY;QACzB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC7D,CAAC;CACF,CAAA;AAZY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;qCAEgB,sBAAa;GAD7B,WAAW,CAYvB"}

5
dist/events/dto/create-event.dto.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
export declare class CreateEventDto {
name: string;
date: string;
location: string;
}

7
dist/events/dto/create-event.dto.js vendored Normal file
View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateEventDto = void 0;
class CreateEventDto {
}
exports.CreateEventDto = CreateEventDto;
//# sourceMappingURL=create-event.dto.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-event.dto.js","sourceRoot":"","sources":["../../../src/events/dto/create-event.dto.ts"],"names":[],"mappings":";;;AAAA,MAAa,cAAc;CAI1B;AAJD,wCAIC"}

5
dist/events/dto/update-event.dto.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import { CreateEventDto } from './create-event.dto';
declare const UpdateEventDto_base: import("@nestjs/mapped-types").MappedType<Partial<CreateEventDto>>;
export declare class UpdateEventDto extends UpdateEventDto_base {
}
export {};

9
dist/events/dto/update-event.dto.js vendored Normal file
View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateEventDto = void 0;
const mapped_types_1 = require("@nestjs/mapped-types");
const create_event_dto_1 = require("./create-event.dto");
class UpdateEventDto extends (0, mapped_types_1.PartialType)(create_event_dto_1.CreateEventDto) {
}
exports.UpdateEventDto = UpdateEventDto;
//# sourceMappingURL=update-event.dto.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"update-event.dto.js","sourceRoot":"","sources":["../../../src/events/dto/update-event.dto.ts"],"names":[],"mappings":";;;AAAA,uDAAmD;AACnD,yDAAoD;AAEpD,MAAa,cAAe,SAAQ,IAAA,0BAAW,EAAC,iCAAc,CAAC;CAAG;AAAlE,wCAAkE"}

View File

@@ -0,0 +1,2 @@
export declare class Event {
}

7
dist/events/entities/event.entity.js vendored Normal file
View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Event = void 0;
class Event {
}
exports.Event = Event;
//# sourceMappingURL=event.entity.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"event.entity.js","sourceRoot":"","sources":["../../../src/events/entities/event.entity.ts"],"names":[],"mappings":";;;AAAA,MAAa,KAAK;CAAG;AAArB,sBAAqB"}

18
dist/events/events.controller.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
import { EventsService } from './events.service';
import { CreateEventDto } from './dto/create-event.dto';
export declare class EventsController {
private readonly eventsService;
constructor(eventsService: EventsService);
create(createEventDto: CreateEventDto): import(".prisma/client").Prisma.Prisma__EventClient<{
id: string;
name: string;
date: string;
location: string;
}, never, import("@prisma/client/runtime/library").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
findAll(): import(".prisma/client").Prisma.PrismaPromise<{
id: string;
name: string;
date: string;
location: string;
}[]>;
}

48
dist/events/events.controller.js vendored Normal file
View File

@@ -0,0 +1,48 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventsController = void 0;
const common_1 = require("@nestjs/common");
const events_service_1 = require("./events.service");
const create_event_dto_1 = require("./dto/create-event.dto");
let EventsController = class EventsController {
constructor(eventsService) {
this.eventsService = eventsService;
}
create(createEventDto) {
return this.eventsService.create(createEventDto);
}
findAll() {
return this.eventsService.findAll();
}
};
exports.EventsController = EventsController;
__decorate([
(0, common_1.Post)(),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [create_event_dto_1.CreateEventDto]),
__metadata("design:returntype", void 0)
], EventsController.prototype, "create", null);
__decorate([
(0, common_1.Get)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], EventsController.prototype, "findAll", null);
exports.EventsController = EventsController = __decorate([
(0, common_1.Controller)('events'),
__metadata("design:paramtypes", [events_service_1.EventsService])
], EventsController);
//# sourceMappingURL=events.controller.js.map

1
dist/events/events.controller.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"events.controller.js","sourceRoot":"","sources":["../../src/events/events.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA6D;AAC7D,qDAAiD;AACjD,6DAAwD;AAGjD,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAG7D,MAAM,CAAS,cAA8B;QAC3C,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;IAGD,OAAO;QACL,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;IACtC,CAAC;CACF,CAAA;AAZY,4CAAgB;AAI3B;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAiB,iCAAc;;8CAE5C;AAGD;IADC,IAAA,YAAG,GAAE;;;;+CAGL;2BAXU,gBAAgB;IAD5B,IAAA,mBAAU,EAAC,QAAQ,CAAC;qCAEyB,8BAAa;GAD9C,gBAAgB,CAY5B"}

2
dist/events/events.module.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class EventsModule {
}

24
dist/events/events.module.js vendored Normal file
View File

@@ -0,0 +1,24 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventsModule = void 0;
const common_1 = require("@nestjs/common");
const events_service_1 = require("./events.service");
const events_controller_1 = require("./events.controller");
const prisma_module_1 = require("../prisma/prisma.module");
let EventsModule = class EventsModule {
};
exports.EventsModule = EventsModule;
exports.EventsModule = EventsModule = __decorate([
(0, common_1.Module)({
imports: [prisma_module_1.PrismaModule],
controllers: [events_controller_1.EventsController],
providers: [events_service_1.EventsService],
})
], EventsModule);
//# sourceMappingURL=events.module.js.map

1
dist/events/events.module.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"events.module.js","sourceRoot":"","sources":["../../src/events/events.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AACjD,2DAAuD;AACvD,2DAAuD;AAOhD,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,CAAC,8BAAa,CAAC;KAC3B,CAAC;GACW,YAAY,CAAG"}

18
dist/events/events.service.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
import { CreateEventDto } from './dto/create-event.dto';
import { PrismaService } from '../prisma/prisma.service';
export declare class EventsService {
private prisma;
constructor(prisma: PrismaService);
create(createEventDto: CreateEventDto): import(".prisma/client").Prisma.Prisma__EventClient<{
id: string;
name: string;
date: string;
location: string;
}, never, import("@prisma/client/runtime/library").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
findAll(): import(".prisma/client").Prisma.PrismaPromise<{
id: string;
name: string;
date: string;
location: string;
}[]>;
}

31
dist/events/events.service.js vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventsService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
let EventsService = class EventsService {
constructor(prisma) {
this.prisma = prisma;
}
create(createEventDto) {
return this.prisma.event.create({ data: createEventDto });
}
findAll() {
return this.prisma.event.findMany();
}
};
exports.EventsService = EventsService;
exports.EventsService = EventsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], EventsService);
//# sourceMappingURL=events.service.js.map

1
dist/events/events.service.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"events.service.js","sourceRoot":"","sources":["../../src/events/events.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,6DAAyD;AAGlD,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE7C,MAAM,CAAC,cAA8B;QACnC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACtC,CAAC;CACF,CAAA;AAVY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAEiB,8BAAa;GAD9B,aAAa,CAUzB"}

2
dist/mail/mail.module.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class MailModule {
}

23
dist/mail/mail.module.js vendored Normal file
View File

@@ -0,0 +1,23 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MailModule = void 0;
const common_1 = require("@nestjs/common");
const mail_service_1 = require("./mail.service");
const config_1 = require("@nestjs/config");
let MailModule = class MailModule {
};
exports.MailModule = MailModule;
exports.MailModule = MailModule = __decorate([
(0, common_1.Module)({
imports: [config_1.ConfigModule],
providers: [mail_service_1.MailService],
exports: [mail_service_1.MailService],
})
], MailModule);
//# sourceMappingURL=mail.module.js.map

1
dist/mail/mail.module.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"mail.module.js","sourceRoot":"","sources":["../../src/mail/mail.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,iDAA6C;AAC7C,2CAA8C;AAOvC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IALtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,qBAAY,CAAC;QACvB,SAAS,EAAE,CAAC,0BAAW,CAAC;QACxB,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;GACW,UAAU,CAAG"}

7
dist/mail/mail.service.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
import { ConfigService } from '@nestjs/config';
export declare class MailService {
private configService;
private transporter;
constructor(configService: ConfigService);
sendTicket(email: string, name: string, ticketId: string, eventName: string, qrCodeBuffer: Buffer): Promise<void>;
}

96
dist/mail/mail.service.js vendored Normal file
View File

@@ -0,0 +1,96 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MailService = void 0;
const common_1 = require("@nestjs/common");
const nodemailer = require("nodemailer");
const config_1 = require("@nestjs/config");
const path = require("path");
let MailService = class MailService {
constructor(configService) {
this.configService = configService;
this.transporter = nodemailer.createTransport({
host: this.configService.get('SMTP_HOST'),
port: this.configService.get('SMTP_PORT'),
secure: this.configService.get('SMTP_SECURE') === 'true',
auth: {
user: this.configService.get('SMTP_USER'),
pass: this.configService.get('SMTP_PASS'),
},
});
}
async sendTicket(email, name, ticketId, eventName, qrCodeBuffer) {
const logoPath = path.join(process.cwd(), 'dist/assets/atiw-out-logo.svg');
const firstName = name.split(' ')[0];
await this.transporter.sendMail({
from: this.configService.get('SMTP_FROM') || '"Event Team" <noreply@example.com>',
to: email,
subject: `Dein Ticket fürs ATIW OUT!`,
html: `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color: #f4f4f5; margin: 0; padding: 0; }
.container { max-width: 600px; margin: 32px auto; background-color: #ffffff; border-radius: 8px; overflow: hidden; border: 1px solid rgba(0, 0, 0, 0.2); padding: 32px; }
.header { background-color: #ffffff; text-align: center; }
.logo { height: 150px;}
.content {text-align: center; color: #333333; }
.greeting { font-size: 32px; color: #18181b; }
.text { font-size: 16px; line-height: 1.5; color: #52525b;}
.qr-container { background-color: #f4f4f5; padding: 24px; border-radius: 12px; display: inline-block; margin: 32px 0px; }
.footer { background-color: #fafafa; padding: 24px; text-align: center; font-size: 14px; color: #a1a1aa; border-top: 1px solid #e4e4e7; }
.highlight { color: #2563eb; font-weight: 600; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<img src="cid:logo" alt="Logo" class="logo" />
</div>
<div class="content">
<h2 class="greeting">Moin Max,</h2>
<p class="text">Hier ist dein Ticket für das <strong>ATIW OUT</strong>!</p>
<p class="text">Zeig diesen QR Code einfach am <strong>09.12.</strong> am Eingang vor.</p>
<div class="qr-container">
<img src="cid:qrcode" width="200" height="200" alt="Dein Ticket QR Code" style="display: block;"/>
</div>
<p class="text">Wir wünschen dir viel Spaß!</p>
<p class="text">~FI231 & FS231</p>
<p class="text" style="margin-top: 32px;">Bei Fragen oder Problemen komm bitte<br>zum Klassenraum <strong>E.07</strong> und frag nach <strong>Jason</strong></p>
</div>
</div>
</body>
</html>
`,
attachments: [
{
filename: 'qrcode.png',
content: qrCodeBuffer,
cid: 'qrcode',
},
{
filename: 'logo.svg',
path: logoPath,
cid: 'logo',
},
],
});
}
};
exports.MailService = MailService;
exports.MailService = MailService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService])
], MailService);
//# sourceMappingURL=mail.service.js.map

1
dist/mail/mail.service.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"mail.service.js","sourceRoot":"","sources":["../../src/mail/mail.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,yCAAyC;AACzC,2CAA+C;AAC/C,6BAA6B;AAGtB,IAAM,WAAW,GAAjB,MAAM,WAAW;IAGtB,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,eAAe,CAAC;YAC5C,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC;YACjD,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC;YACjD,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,aAAa,CAAC,KAAK,MAAM;YAChE,IAAI,EAAE;gBACJ,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC;gBACjD,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC;aAClD;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CACd,KAAa,EACb,IAAY,EACZ,QAAgB,EAChB,SAAiB,EACjB,YAAoB;QAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,+BAA+B,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAErC,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;YAC9B,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC,IAAI,oCAAoC;YACzF,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,4BAA4B;YACrC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCL;YACD,WAAW,EAAE;gBACX;oBACE,QAAQ,EAAE,YAAY;oBACtB,OAAO,EAAE,YAAY;oBACrB,GAAG,EAAE,QAAQ;iBACd;gBACD;oBACE,QAAQ,EAAE,UAAU;oBACpB,IAAI,EAAE,QAAQ;oBACd,GAAG,EAAE,MAAM;iBACZ;aACF;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAlFY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;qCAIwB,sBAAa;GAHrC,WAAW,CAkFvB"}

1
dist/main.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export {};

14
dist/main.js vendored Normal file
View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@nestjs/core");
const app_module_1 = require("./app.module");
const common_1 = require("@nestjs/common");
async function bootstrap() {
const app = await core_1.NestFactory.create(app_module_1.AppModule);
app.setGlobalPrefix('api');
app.enableCors();
app.useGlobalPipes(new common_1.ValidationPipe());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
//# sourceMappingURL=main.js.map

1
dist/main.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAgD;AAEhD,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAChD,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC3B,GAAG,CAAC,UAAU,EAAE,CAAC;IACjB,GAAG,CAAC,cAAc,CAAC,IAAI,uBAAc,EAAE,CAAC,CAAC;IACzC,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC7C,CAAC;AACD,SAAS,EAAE,CAAC"}

2
dist/prisma/prisma.module.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class PrismaModule {
}

22
dist/prisma/prisma.module.js vendored Normal file
View File

@@ -0,0 +1,22 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrismaModule = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("./prisma.service");
let PrismaModule = class PrismaModule {
};
exports.PrismaModule = PrismaModule;
exports.PrismaModule = PrismaModule = __decorate([
(0, common_1.Global)(),
(0, common_1.Module)({
providers: [prisma_service_1.PrismaService],
exports: [prisma_service_1.PrismaService],
})
], PrismaModule);
//# sourceMappingURL=prisma.module.js.map

1
dist/prisma/prisma.module.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"prisma.module.js","sourceRoot":"","sources":["../../src/prisma/prisma.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,qDAAiD;AAO1C,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,8BAAa,CAAC;QAC1B,OAAO,EAAE,CAAC,8BAAa,CAAC;KACzB,CAAC;GACW,YAAY,CAAG"}

6
dist/prisma/prisma.service.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
export declare class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
onModuleInit(): Promise<void>;
onModuleDestroy(): Promise<void>;
}

24
dist/prisma/prisma.service.js vendored Normal file
View File

@@ -0,0 +1,24 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrismaService = void 0;
const common_1 = require("@nestjs/common");
const client_1 = require("@prisma/client");
let PrismaService = class PrismaService extends client_1.PrismaClient {
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
};
exports.PrismaService = PrismaService;
exports.PrismaService = PrismaService = __decorate([
(0, common_1.Injectable)()
], PrismaService);
//# sourceMappingURL=prisma.service.js.map

1
dist/prisma/prisma.service.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"prisma.service.js","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA2E;AAC3E,2CAA8C;AAGvC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,qBAAY;IAC7C,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AARY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAQzB"}

View File

@@ -0,0 +1,6 @@
export declare class CreateTicketDto {
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
}

33
dist/tickets/dto/create-ticket.dto.js vendored Normal file
View File

@@ -0,0 +1,33 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateTicketDto = void 0;
const class_validator_1 = require("class-validator");
class CreateTicketDto {
}
exports.CreateTicketDto = CreateTicketDto;
__decorate([
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], CreateTicketDto.prototype, "eventId", void 0);
__decorate([
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], CreateTicketDto.prototype, "attendeeName", void 0);
__decorate([
(0, class_validator_1.IsEmail)(),
__metadata("design:type", String)
], CreateTicketDto.prototype, "attendeeEmail", void 0);
__decorate([
(0, class_validator_1.IsIn)(['Klassenbester', '1er Schüler', 'Partyborner']),
__metadata("design:type", String)
], CreateTicketDto.prototype, "ticketType", void 0);
//# sourceMappingURL=create-ticket.dto.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-ticket.dto.js","sourceRoot":"","sources":["../../../src/tickets/dto/create-ticket.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA0D;AAE1D,MAAa,eAAe;CAY3B;AAZD,0CAYC;AAVC;IADC,IAAA,0BAAQ,GAAE;;gDACK;AAGhB;IADC,IAAA,0BAAQ,GAAE;;qDACU;AAGrB;IADC,IAAA,yBAAO,GAAE;;sDACY;AAGtB;IADC,IAAA,sBAAI,EAAC,CAAC,eAAe,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;;mDACnC"}

View File

@@ -0,0 +1,5 @@
import { CreateTicketDto } from './create-ticket.dto';
declare const UpdateTicketDto_base: import("@nestjs/mapped-types").MappedType<Partial<CreateTicketDto>>;
export declare class UpdateTicketDto extends UpdateTicketDto_base {
}
export {};

9
dist/tickets/dto/update-ticket.dto.js vendored Normal file
View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateTicketDto = void 0;
const mapped_types_1 = require("@nestjs/mapped-types");
const create_ticket_dto_1 = require("./create-ticket.dto");
class UpdateTicketDto extends (0, mapped_types_1.PartialType)(create_ticket_dto_1.CreateTicketDto) {
}
exports.UpdateTicketDto = UpdateTicketDto;
//# sourceMappingURL=update-ticket.dto.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"update-ticket.dto.js","sourceRoot":"","sources":["../../../src/tickets/dto/update-ticket.dto.ts"],"names":[],"mappings":";;;AAAA,uDAAmD;AACnD,2DAAsD;AAEtD,MAAa,eAAgB,SAAQ,IAAA,0BAAW,EAAC,mCAAe,CAAC;CAAG;AAApE,0CAAoE"}

View File

@@ -0,0 +1,2 @@
export declare class Ticket {
}

View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ticket = void 0;
class Ticket {
}
exports.Ticket = Ticket;
//# sourceMappingURL=ticket.entity.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ticket.entity.js","sourceRoot":"","sources":["../../../src/tickets/entities/ticket.entity.ts"],"names":[],"mappings":";;;AAAA,MAAa,MAAM;CAAG;AAAtB,wBAAsB"}

53
dist/tickets/tickets.controller.d.ts vendored Normal file
View File

@@ -0,0 +1,53 @@
import { TicketsService } from './tickets.service';
import { CreateTicketDto } from './dto/create-ticket.dto';
export declare class TicketsController {
private readonly ticketsService;
constructor(ticketsService: TicketsService);
create(createTicketDto: CreateTicketDto): Promise<{
event: {
id: string;
name: string;
date: string;
location: string;
};
} & {
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}>;
findAll(eventId: string): import(".prisma/client").Prisma.PrismaPromise<{
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}[]>;
resendEmail(id: string): Promise<{
success: boolean;
message: string;
}>;
updateStatus(id: string, status: string): import(".prisma/client").Prisma.Prisma__TicketClient<{
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}, never, import("@prisma/client/runtime/library").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
remove(id: string): import(".prisma/client").Prisma.Prisma__TicketClient<{
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}, never, import("@prisma/client/runtime/library").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
}

80
dist/tickets/tickets.controller.js vendored Normal file
View File

@@ -0,0 +1,80 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TicketsController = void 0;
const common_1 = require("@nestjs/common");
const tickets_service_1 = require("./tickets.service");
const create_ticket_dto_1 = require("./dto/create-ticket.dto");
let TicketsController = class TicketsController {
constructor(ticketsService) {
this.ticketsService = ticketsService;
}
create(createTicketDto) {
return this.ticketsService.create(createTicketDto);
}
findAll(eventId) {
return this.ticketsService.findAll(eventId);
}
resendEmail(id) {
return this.ticketsService.resendEmail(id);
}
updateStatus(id, status) {
return this.ticketsService.updateStatus(id, status);
}
remove(id) {
return this.ticketsService.remove(id);
}
};
exports.TicketsController = TicketsController;
__decorate([
(0, common_1.Post)(),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [create_ticket_dto_1.CreateTicketDto]),
__metadata("design:returntype", void 0)
], TicketsController.prototype, "create", null);
__decorate([
(0, common_1.Get)(),
__param(0, (0, common_1.Query)('eventId')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], TicketsController.prototype, "findAll", null);
__decorate([
(0, common_1.Post)(':id/resend'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], TicketsController.prototype, "resendEmail", null);
__decorate([
(0, common_1.Put)(':id/status'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)('status')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", void 0)
], TicketsController.prototype, "updateStatus", null);
__decorate([
(0, common_1.Delete)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], TicketsController.prototype, "remove", null);
exports.TicketsController = TicketsController = __decorate([
(0, common_1.Controller)('tickets'),
__metadata("design:paramtypes", [tickets_service_1.TicketsService])
], TicketsController);
//# sourceMappingURL=tickets.controller.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"tickets.controller.js","sourceRoot":"","sources":["../../src/tickets/tickets.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwF;AACxF,uDAAmD;AACnD,+DAA0D;AAGnD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC5B,YAA6B,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAAG,CAAC;IAG/D,MAAM,CAAS,eAAgC;QAC7C,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACrD,CAAC;IAGD,OAAO,CAAmB,OAAe;QACvC,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAGD,WAAW,CAAc,EAAU;QACjC,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC;IAGD,YAAY,CAAc,EAAU,EAAkB,MAAc;QAClE,OAAO,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAGD,MAAM,CAAc,EAAU;QAC5B,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;CACF,CAAA;AA3BY,8CAAiB;AAI5B;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAkB,mCAAe;;+CAE9C;AAGD;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,SAAS,CAAC,CAAA;;;;gDAExB;AAGD;IADC,IAAA,aAAI,EAAC,YAAY,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;oDAEvB;AAGD;IADC,IAAA,YAAG,EAAC,YAAY,CAAC;IACJ,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,EAAC,QAAQ,CAAC,CAAA;;;;qDAEpD;AAGD;IADC,IAAA,eAAM,EAAC,KAAK,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;+CAElB;4BA1BU,iBAAiB;IAD7B,IAAA,mBAAU,EAAC,SAAS,CAAC;qCAEyB,gCAAc;GADhD,iBAAiB,CA2B7B"}

2
dist/tickets/tickets.module.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class TicketsModule {
}

25
dist/tickets/tickets.module.js vendored Normal file
View File

@@ -0,0 +1,25 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TicketsModule = void 0;
const common_1 = require("@nestjs/common");
const tickets_service_1 = require("./tickets.service");
const tickets_controller_1 = require("./tickets.controller");
const prisma_module_1 = require("../prisma/prisma.module");
const mail_module_1 = require("../mail/mail.module");
let TicketsModule = class TicketsModule {
};
exports.TicketsModule = TicketsModule;
exports.TicketsModule = TicketsModule = __decorate([
(0, common_1.Module)({
imports: [prisma_module_1.PrismaModule, mail_module_1.MailModule],
controllers: [tickets_controller_1.TicketsController],
providers: [tickets_service_1.TicketsService],
})
], TicketsModule);
//# sourceMappingURL=tickets.module.js.map

1
dist/tickets/tickets.module.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"tickets.module.js","sourceRoot":"","sources":["../../src/tickets/tickets.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uDAAmD;AACnD,6DAAyD;AACzD,2DAAuD;AACvD,qDAAiD;AAO1C,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IALzB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,wBAAU,CAAC;QACnC,WAAW,EAAE,CAAC,sCAAiB,CAAC;QAChC,SAAS,EAAE,CAAC,gCAAc,CAAC;KAC5B,CAAC;GACW,aAAa,CAAG"}

55
dist/tickets/tickets.service.d.ts vendored Normal file
View File

@@ -0,0 +1,55 @@
import { CreateTicketDto } from './dto/create-ticket.dto';
import { PrismaService } from '../prisma/prisma.service';
import { MailService } from '../mail/mail.service';
export declare class TicketsService {
private prisma;
private mailService;
constructor(prisma: PrismaService, mailService: MailService);
create(createTicketDto: CreateTicketDto): Promise<{
event: {
id: string;
name: string;
date: string;
location: string;
};
} & {
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}>;
findAll(eventId: string): import(".prisma/client").Prisma.PrismaPromise<{
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}[]>;
resendEmail(id: string): Promise<{
success: boolean;
message: string;
}>;
updateStatus(id: string, status: string): import(".prisma/client").Prisma.Prisma__TicketClient<{
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}, never, import("@prisma/client/runtime/library").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
remove(id: string): import(".prisma/client").Prisma.Prisma__TicketClient<{
id: string;
eventId: string;
attendeeName: string;
attendeeEmail: string;
ticketType: string;
status: string;
createdAt: Date;
}, never, import("@prisma/client/runtime/library").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
}

93
dist/tickets/tickets.service.js vendored Normal file
View File

@@ -0,0 +1,93 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TicketsService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
const mail_service_1 = require("../mail/mail.service");
const QRCode = require("qrcode");
let TicketsService = class TicketsService {
constructor(prisma, mailService) {
this.prisma = prisma;
this.mailService = mailService;
}
async create(createTicketDto) {
const ticket = await this.prisma.ticket.create({
data: createTicketDto,
include: { event: true },
});
try {
const qrCodeBuffer = await QRCode.toBuffer(ticket.id, {
errorCorrectionLevel: 'H',
type: 'png',
width: 250,
color: {
dark: '#000000',
light: '#FFFFFF',
},
});
await this.mailService.sendTicket(ticket.attendeeEmail, ticket.attendeeName, ticket.id, ticket.event.name, qrCodeBuffer);
}
catch (error) {
console.error('Failed to send ticket email:', error);
}
return ticket;
}
findAll(eventId) {
return this.prisma.ticket.findMany({
where: { eventId },
});
}
async resendEmail(id) {
const ticket = await this.prisma.ticket.findUnique({
where: { id },
include: { event: true },
});
if (!ticket) {
throw new Error('Ticket not found');
}
try {
const qrCodeBuffer = await QRCode.toBuffer(ticket.id, {
errorCorrectionLevel: 'H',
type: 'png',
width: 250,
color: {
dark: '#000000',
light: '#FFFFFF',
},
});
await this.mailService.sendTicket(ticket.attendeeEmail, ticket.attendeeName, ticket.id, ticket.event.name, qrCodeBuffer);
return { success: true, message: 'Email resent successfully' };
}
catch (error) {
console.error('Failed to resend ticket email:', error);
throw new Error('Failed to send email');
}
}
updateStatus(id, status) {
return this.prisma.ticket.update({
where: { id },
data: { status },
});
}
remove(id) {
return this.prisma.ticket.delete({
where: { id },
});
}
};
exports.TicketsService = TicketsService;
exports.TicketsService = TicketsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
mail_service_1.MailService])
], TicketsService);
//# sourceMappingURL=tickets.service.js.map

Some files were not shown because too many files have changed in this diff Show More