womp womp
This commit is contained in:
parent
3e95e2d4f2
commit
b96fb0d0e4
4 changed files with 74 additions and 32 deletions
|
|
@ -39,7 +39,14 @@ public class AuthService {
|
||||||
user.setName(request.getFirstname() + " " + request.getLastname()); // Populate legacy/fallback fields
|
user.setName(request.getFirstname() + " " + request.getLastname()); // Populate legacy/fallback fields
|
||||||
user.setEmail(request.getEmail());
|
user.setEmail(request.getEmail());
|
||||||
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
||||||
user.setRole(request.getRole());
|
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) {
|
if ("RAUMBETREUER".equals(request.getRole()) && request.getRoomIds() != null) {
|
||||||
List<Room> rooms = roomRepository.findAllById(request.getRoomIds());
|
List<Room> rooms = roomRepository.findAllById(request.getRoomIds());
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||||
import { ShieldAlert, Users } from "lucide-react"
|
import { ShieldAlert, Users } from "lucide-react"
|
||||||
|
|
||||||
export function AdminDashboard() {
|
export function AdminDashboard() {
|
||||||
const { tickets, updateTicketStatus, authHeader } = useAuth()
|
const { tickets, updateTicketStatus, deleteTicket, authHeader } = useAuth()
|
||||||
const API_URL = process.env.NEXT_PUBLIC_API_URL + "/api"
|
const API_URL = process.env.NEXT_PUBLIC_API_URL + "/api"
|
||||||
|
|
||||||
// Admin sees all tickets (logic handled in Backend/TicketService)
|
// Admin sees all tickets (logic handled in Backend/TicketService)
|
||||||
|
|
@ -62,6 +62,7 @@ export function AdminDashboard() {
|
||||||
tickets={tickets}
|
tickets={tickets}
|
||||||
showStatusUpdate
|
showStatusUpdate
|
||||||
onStatusUpdate={updateTicketStatus}
|
onStatusUpdate={updateTicketStatus}
|
||||||
|
onDeleteTicket={deleteTicket}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} 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 { Input } from "@/components/ui/input"
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||||
import { TicketComments } from "./ticket-comments"
|
import { TicketComments } from "./ticket-comments"
|
||||||
|
|
@ -20,11 +21,12 @@ interface TicketTableProps {
|
||||||
tickets: Ticket[]
|
tickets: Ticket[]
|
||||||
showStatusUpdate?: boolean
|
showStatusUpdate?: boolean
|
||||||
onStatusUpdate?: (ticketId: number, status: TicketStatus) => void
|
onStatusUpdate?: (ticketId: number, status: TicketStatus) => void
|
||||||
|
onDeleteTicket?: (ticketId: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type SortDirection = "asc" | "desc"
|
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 [sortConfig, setSortConfig] = useState<{ key: keyof Ticket | "room" | "owner"; direction: SortDirection }>({ key: "createdAt", direction: "desc" })
|
||||||
const [search, setSearch] = useState("")
|
const [search, setSearch] = useState("")
|
||||||
const [statusFilter, setStatusFilter] = useState<TicketStatus | "ALL">("ALL")
|
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")}>
|
<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" />)}
|
Status {sortConfig.key === "status" && (sortConfig.direction === "asc" ? <ArrowUp className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />)}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
|
{onDeleteTicket && <TableHead className="w-[50px]"></TableHead>}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
|
@ -174,6 +177,23 @@ export function TicketTable({ tickets, showStatusUpdate = false, onStatusUpdate
|
||||||
<StatusBadge status={ticket.status} />
|
<StatusBadge status={ticket.status} />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</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>
|
</TableRow>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ interface AuthContextType {
|
||||||
logout: () => void
|
logout: () => void
|
||||||
createTicket: (ticket: { roomId: number; title: string; description: string }) => Promise<void>
|
createTicket: (ticket: { roomId: number; title: string; description: string }) => Promise<void>
|
||||||
updateTicketStatus: (ticketId: number, status: TicketStatus) => Promise<void>
|
updateTicketStatus: (ticketId: number, status: TicketStatus) => Promise<void>
|
||||||
|
deleteTicket: (ticketId: number) => Promise<void>
|
||||||
updateRooms: (roomIds: number[]) => Promise<void>
|
updateRooms: (roomIds: number[]) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,33 +177,46 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(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)
|
||||||
|
}
|
||||||
|
}, [authHeader, fetchTickets])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider
|
||||||
|
value={{
|
||||||
|
user,
|
||||||
|
tickets,
|
||||||
|
rooms,
|
||||||
|
authHeader,
|
||||||
|
login,
|
||||||
|
register,
|
||||||
|
logout,
|
||||||
|
createTicket,
|
||||||
|
updateTicketStatus,
|
||||||
|
deleteTicket,
|
||||||
|
updateRooms,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}, [authHeader, fetchTickets])
|
|
||||||
|
|
||||||
return (
|
export function useAuth() {
|
||||||
<AuthContext.Provider
|
const context = useContext(AuthContext)
|
||||||
value={{
|
if (!context) {
|
||||||
user,
|
throw new Error("useAuth must be used within an AuthProvider")
|
||||||
tickets,
|
}
|
||||||
rooms,
|
return context
|
||||||
authHeader,
|
}
|
||||||
login,
|
|
||||||
register,
|
|
||||||
logout,
|
|
||||||
createTicket,
|
|
||||||
updateTicketStatus,
|
|
||||||
updateRooms,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</AuthContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAuth() {
|
|
||||||
const context = useContext(AuthContext)
|
|
||||||
if (!context) {
|
|
||||||
throw new Error("useAuth must be used within an AuthProvider")
|
|
||||||
}
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue