womp womp

This commit is contained in:
Hymmel 2026-01-21 11:50:23 +01:00
parent 3e95e2d4f2
commit b96fb0d0e4
4 changed files with 74 additions and 32 deletions

View file

@ -39,7 +39,14 @@ public class AuthService {
user.setName(request.getFirstname() + " " + request.getLastname()); // Populate legacy/fallback fields
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword()));
user.setPassword(passwordEncoder.encode(request.getPassword()));
// Auto-assign ADMIN role to the very first user
if (userRepository.count() == 0) {
user.setRole("ADMIN");
} else {
user.setRole(request.getRole());
}
if ("RAUMBETREUER".equals(request.getRole()) && request.getRoomIds() != null) {
List<Room> rooms = roomRepository.findAllById(request.getRoomIds());

View file

@ -7,7 +7,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
import { ShieldAlert, Users } from "lucide-react"
export function AdminDashboard() {
const { tickets, updateTicketStatus, authHeader } = useAuth()
const { tickets, updateTicketStatus, deleteTicket, authHeader } = useAuth()
const API_URL = process.env.NEXT_PUBLIC_API_URL + "/api"
// Admin sees all tickets (logic handled in Backend/TicketService)
@ -62,6 +62,7 @@ export function AdminDashboard() {
tickets={tickets}
showStatusUpdate
onStatusUpdate={updateTicketStatus}
onDeleteTicket={deleteTicket}
/>
</CardContent>
</Card>

View file

@ -11,7 +11,8 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { ArrowUpDown, ArrowDown, ArrowUp, Calendar, MapPin, FileText } from "lucide-react"
import { ArrowUpDown, ArrowDown, ArrowUp, Calendar, MapPin, FileText, Trash2 } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { TicketComments } from "./ticket-comments"
@ -20,11 +21,12 @@ interface TicketTableProps {
tickets: Ticket[]
showStatusUpdate?: boolean
onStatusUpdate?: (ticketId: number, status: TicketStatus) => void
onDeleteTicket?: (ticketId: number) => void
}
type SortDirection = "asc" | "desc"
export function TicketTable({ tickets, showStatusUpdate = false, onStatusUpdate }: TicketTableProps) {
export function TicketTable({ tickets, showStatusUpdate = false, onStatusUpdate, onDeleteTicket }: TicketTableProps) {
const [sortConfig, setSortConfig] = useState<{ key: keyof Ticket | "room" | "owner"; direction: SortDirection }>({ key: "createdAt", direction: "desc" })
const [search, setSearch] = useState("")
const [statusFilter, setStatusFilter] = useState<TicketStatus | "ALL">("ALL")
@ -133,6 +135,7 @@ export function TicketTable({ tickets, showStatusUpdate = false, onStatusUpdate
<TableHead className="font-semibold cursor-pointer" onClick={() => handleSort("status")}>
Status {sortConfig.key === "status" && (sortConfig.direction === "asc" ? <ArrowUp className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />)}
</TableHead>
{onDeleteTicket && <TableHead className="w-[50px]"></TableHead>}
</TableRow>
</TableHeader>
<TableBody>
@ -174,6 +177,23 @@ export function TicketTable({ tickets, showStatusUpdate = false, onStatusUpdate
<StatusBadge status={ticket.status} />
)}
</TableCell>
{onDeleteTicket && (
<TableCell onClick={(e) => e.stopPropagation()}>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-destructive hover:text-destructive hover:bg-destructive/10"
onClick={(e) => {
e.stopPropagation()
if (confirm("Ticket wirklich löschen?")) {
onDeleteTicket(ticket.id)
}
}}
>
<Trash2 className="h-4 w-4" />
</Button>
</TableCell>
)}
</TableRow>
))
)}

View file

@ -16,6 +16,7 @@ interface AuthContextType {
logout: () => void
createTicket: (ticket: { roomId: number; title: string; description: string }) => Promise<void>
updateTicketStatus: (ticketId: number, status: TicketStatus) => Promise<void>
deleteTicket: (ticketId: number) => Promise<void>
updateRooms: (roomIds: number[]) => Promise<void>
}
@ -174,6 +175,18 @@ export function AuthProvider({ children }: { children: ReactNode }) {
if (res.ok) {
fetchTickets(authHeader) // Refresh
}
} catch (e) {
console.error(e)
const deleteTicket = useCallback(async (ticketId: number) => {
if (!authHeader) return
try {
const res = await fetch(`${API_URL}/tickets/${ticketId}`, {
method: "DELETE",
headers: { "Authorization": authHeader }
})
if (res.ok) {
fetchTickets(authHeader)
}
} catch (e) {
console.error(e)
}
@ -191,6 +204,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
logout,
createTicket,
updateTicketStatus,
deleteTicket,
updateRooms,
}}
>