import axios from "axios"; import { useState } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Maximize2, Minimize2, Trash2Icon } from "lucide-react"; import GroupPermission from "./group-permission"; import { z } from "zod"; import UserList from "./user-list-group"; const groupNameSchema = z.string({ required_error: "Group name is required.", invalid_type_error: "Group name must be a string" }).regex(/^[\w\-\s]{1,20}$/, "Group name must contain only letters, numbers, spaces, dashes, and underscores.") const prioritySchema = z.string().regex(/^-?\d{1,5}$/, "Priority must be a valid number.") interface Group { id: string | undefined name: string priority: number permissionsLoaded: { id: string, path: string, allow: boolean | null }[] edit: boolean showEdit: boolean isNewGroup: boolean permissionPaths: { path: string, description: string }[] specialGroups: string[] adder: (id: string, name: string, priority: number) => void remover: (group: { id: string, name: string, priority: number }) => void, contains: (groupName: string) => boolean } const GroupElement = ({ id, name, priority, permissionsLoaded, edit, showEdit, isNewGroup, permissionPaths, specialGroups, adder, remover, contains }: Group) => { const [isEditable, setIsEditable] = useState(edit) const [isNew, setIsNew] = useState(isNewGroup) const [isMinimized, setIsMinimized] = useState(true) const [oldData, setOldData] = useState<{ id: string | undefined, name: string, priority: number } | undefined>(undefined) const [group, setGroup] = useState<{ id: string | undefined, name: string, priority: number }>({ id, name, priority }) const [permissions, setPermissions] = useState<{ id: string, path: string, allow: boolean | null }[]>(permissionsLoaded); const isSpecial = (isEditable || oldData === undefined) && !!group && specialGroups.includes(group?.name) const [error, setError] = useState(undefined) function addPermission(id: string, path: string, allow: boolean | null) { setPermissions([...permissions, { id, path, allow }]) } function removePermission(permission: { id: string, path: string, allow: boolean | null }) { setPermissions(permissions.filter(p => p.id != permission.id)) } function containsPermission(path: string) { return permissions.some(p => p.path == path) } function Save() { setError(undefined) if (!isNew && !id) { setError("Something went wrong.") return } if (!group.name) { setError("Set a value for the group name") return } const groupNameValidation = groupNameSchema.safeParse(group.name) if (!groupNameValidation.success) { setError(JSON.parse(groupNameValidation.error['message'])[0].message) return } const priorityValidation = prioritySchema.safeParse(group.priority.toString()) if (!priorityValidation.success) { setError(JSON.parse(priorityValidation.error['message'])[0].message) return } if (isNew || group.id?.startsWith('$')) { if (contains(group.name) && !isSpecial) { setError("Group already exists. Use another name.") return; } axios.post("/api/settings/groups", { name: group.name, priority: group.priority }).then(d => { if (!d) { setError("Something went wrong.") return } if (specialGroups.includes(group.name)) { setIsNew(false) setIsEditable(false) setGroup({ id: d.data.id, name: d.data.name, priority: d.data.priority }) } else { adder(d.data.id, group.name.toLowerCase(), group.priority) setGroup({ id: undefined, name: "", priority: 0 }) } }).catch(() => { setError("Something went wrong.") }) } else { if (!contains(group.name)) { setError("Group does not exist. Something went wrong.") return; } axios.put("/api/settings/groups", { id: group.id, name: group.name, priority: group.priority }).then(d => { setIsEditable(false) }).catch(() => { setError("Something went wrong.") }) } } function Cancel() { if (!oldData) return setError(undefined) setGroup({ ...oldData, id: group.id }) setIsEditable(false) setOldData(undefined) } function Delete() { if (!group.id) { return; } if (!contains(oldData?.name ?? group.name)) { if (oldData?.id) remover({ ...oldData, id: oldData.id }) else remover({ ...group, id: group.id }) return; } axios.delete("/api/settings/groups?id=" + group.id) .then(d => { if (specialGroups.includes(group.name)) { setPermissions([]) setIsMinimized(true) setOldData(undefined) setIsNew(true) setIsEditable(true) } else remover(d.data) }) } return (
{isSpecial &&
auto-generated
} setGroup({ ...group, name: e.target.value })} readOnly={isSpecial || !isEditable} />
setGroup(d => { let temp = { ...group } const v = parseInt(e.target.value) if (e.target.value.length == 0 || Number.isNaN(v)) { temp.priority = 0 } else if (!Number.isNaN(v) && Number.isSafeInteger(v)) { temp.priority = v } return temp })} readOnly={!isEditable} />

{error}

{isEditable && } {isEditable && !isNew && } {showEdit && !isEditable && } {!isEditable && !isNew && } {!isNew && !group?.id?.startsWith('$') && } {!isNew && !isSpecial && }
{!isNew && !isMinimized &&
{permissions.map(permission =>
)}
}
); } export default GroupElement;