/* eslint-disable @next/next/no-img-element */ import CardList from "@/components/High/CardList"; import Select from "@/components/Low/Select"; import Input from "@/components/Low/Input"; import Checkbox from "@/components/Low/Checkbox"; import Tooltip from "@/components/Low/Tooltip"; import { useEntityPermission } from "@/hooks/useEntityPermissions"; import { EntityWithRoles, Role } from "@/interfaces/entity"; import { User } from "@/interfaces/user"; import { sessionOptions } from "@/lib/session"; import { USER_TYPE_LABELS } from "@/resources/user"; import { findBy, mapBy, redirect, serialize } from "@/utils"; import { getEntityWithRoles } from "@/utils/entities.be"; import { shouldRedirectHome } from "@/utils/navigation.disabled"; import { doesEntityAllow } from "@/utils/permissions"; import { getUserName, isAdmin } from "@/utils/users"; import { filterAllowedUsers, getEntitiesUsers, getEntityUsers, getUsers } from "@/utils/users.be"; import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; import axios from "axios"; import clsx from "clsx"; import { withIronSessionSsr } from "iron-session/next"; import moment from "moment"; import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import { Divider } from "primereact/divider"; import { useEffect, useState } from "react"; import ReactDatePicker from "react-datepicker"; import { CURRENCIES } from "@/resources/paypal"; import { BsCheck, BsChevronLeft, BsClockFill, BsEnvelopeFill, BsHash, BsPerson, BsPlus, BsStopwatchFill, BsTag, BsTrash, BsX, } from "react-icons/bs"; import { toast } from "react-toastify"; const expirationDateColor = (date: Date) => { const momentDate = moment(date); const today = moment(new Date()); if (today.add(1, "days").isAfter(momentDate)) return "!bg-mti-red-ultralight border-mti-red-light"; if (today.add(3, "days").isAfter(momentDate)) return "!bg-mti-rose-ultralight border-mti-rose-light"; if (today.add(7, "days").isAfter(momentDate)) return "!bg-mti-orange-ultralight border-mti-orange-light"; }; const CURRENCIES_OPTIONS = CURRENCIES.map(({ label, currency }) => ({ value: currency, label, })); export const getServerSideProps = withIronSessionSsr(async ({ req, params }) => { const user = req.session.user as User; if (!user) return redirect("/login") if (shouldRedirectHome(user)) return redirect("/") const { id } = params as { id: string }; const entity = await getEntityWithRoles(id); if (!entity) return redirect("/entities") if (!doesEntityAllow(user, entity, "view_entities")) return redirect(`/entities`) const linkedUsers = await (isAdmin(user) ? getUsers() : getEntitiesUsers(mapBy(user.entities, 'id'), { $and: [{ type: { $ne: "developer" } }, { type: { $ne: "admin" } }] })) const entityUsers = await (isAdmin(user) ? getEntityUsers(id) : filterAllowedUsers(user, [entity])); const usersWithRole = entityUsers.map((u) => { const e = u.entities.find((e) => e.id === id); return { ...u, role: findBy(entity.roles, 'id', e?.role) }; }); return { props: serialize({ user, entity, users: usersWithRole, linkedUsers: linkedUsers.filter(x => x.id !== user.id && !mapBy(entityUsers, 'id').includes(x.id)), }), }; }, sessionOptions); type UserWithRole = User & { role?: Role }; interface Props { user: User; entity: EntityWithRoles; users: UserWithRole[]; linkedUsers: User[]; } export default function Home({ user, entity, users, linkedUsers }: Props) { const [isAdding, setIsAdding] = useState(false); const [isLoading, setIsLoading] = useState(false); const [selectedUsers, setSelectedUsers] = useState([]); const [expiryDate, setExpiryDate] = useState(entity?.expiryDate) const [paymentPrice, setPaymentPrice] = useState(entity?.payment?.price) const [paymentCurrency, setPaymentCurrency] = useState(entity?.payment?.currency) const router = useRouter(); const canRenameEntity = useEntityPermission(user, entity, "rename_entity") const canViewRoles = useEntityPermission(user, entity, "view_entity_roles") const canDeleteEntity = useEntityPermission(user, entity, "delete_entity") const canAddMembers = useEntityPermission(user, entity, "add_to_entity") const canRemoveMembers = useEntityPermission(user, entity, "remove_from_entity") const canAssignRole = useEntityPermission(user, entity, "assign_to_role") const canPay = useEntityPermission(user, entity, 'pay_entity') const toggleUser = (u: User) => setSelectedUsers((prev) => (prev.includes(u.id) ? prev.filter((p) => p !== u.id) : [...prev, u.id])); const removeParticipants = () => { if (selectedUsers.length === 0) return; if (!canRemoveMembers) return; if (!confirm(`Are you sure you want to remove ${selectedUsers.length} member${selectedUsers.length === 1 ? "" : "s"} from this entity?`)) return; setIsLoading(true); axios .patch(`/api/entities/${entity.id}/users`, { add: false, members: selectedUsers }) .then(() => { toast.success("The entity has been updated successfully!"); router.replace(router.asPath); setSelectedUsers([]); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const addParticipants = () => { if (selectedUsers.length === 0) return; if (!canAddMembers || !isAdding) return; if (!confirm(`Are you sure you want to add ${selectedUsers.length} member${selectedUsers.length === 1 ? "" : "s"} to this entity?`)) return; setIsLoading(true); const defaultRole = findBy(entity.roles, 'isDefault', true)! axios .patch(`/api/entities/${entity.id}/users`, { add: true, members: selectedUsers, role: defaultRole.id }) .then(() => { toast.success("The entity has been updated successfully!"); router.replace(router.asPath); setIsAdding(false); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const renameGroup = () => { if (!canRenameEntity) return; const label = prompt("Rename this entity:", entity.label); if (!label) return; setIsLoading(true); axios .patch(`/api/entities/${entity.id}`, { label }) .then(() => { toast.success("The entity has been updated successfully!"); router.replace(router.asPath); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const updateExpiryDate = () => { if (!isAdmin(user)) return; setIsLoading(true); axios .patch(`/api/entities/${entity.id}`, { expiryDate }) .then(() => { toast.success("The entity has been updated successfully!"); router.replace(router.asPath); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const updatePayment = () => { if (!isAdmin(user)) return; setIsLoading(true); axios .patch(`/api/entities/${entity.id}`, { payment: { price: paymentPrice, currency: paymentCurrency } }) .then(() => { toast.success("The entity has been updated successfully!"); router.replace(router.asPath); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const editLicenses = () => { if (!isAdmin(user)) return; const licenses = prompt("Update the number of licenses:", (entity.licenses || 0).toString()); if (!licenses) return; if (!parseInt(licenses) || parseInt(licenses) <= 0) return toast.error("Write a valid number of licenses!") setIsLoading(true); axios .patch(`/api/entities/${entity.id}`, { licenses }) .then(() => { toast.success("The entity has been updated successfully!"); router.replace(router.asPath); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const deleteGroup = () => { if (!canDeleteEntity) return; if (!confirm("Are you sure you want to delete this entity?")) return; setIsLoading(true); axios .delete(`/api/entities/${entity.id}`) .then(() => { toast.success("This entity has been successfully deleted!"); router.replace("/entities"); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); }; const assignUsersToRole = (role: string) => { if (!canAssignRole) return if (selectedUsers.length === 0) return setIsLoading(true); axios .post(`/api/roles/${role}/users`, { users: selectedUsers }) .then(() => { toast.success("The role has been assigned successfully!"); router.replace(router.asPath); }) .catch((e) => { console.error(e); toast.error("Something went wrong!"); }) .finally(() => setIsLoading(false)); } const renderCard = (u: UserWithRole) => { return ( ); }; useEffect(() => setSelectedUsers([]), [isAdding]); return ( <> {entity.label} | EnCoach <>

{entity.label} {isAdmin(user) && `- ${entity.licenses || 0} licenses`}

{!isAdmin(user) && canPay && ( {!entity.expiryDate && "Unlimited"} {entity.expiryDate && moment(entity.expiryDate).format("DD/MM/YYYY")} )}
{isAdmin(user) && ( )}
{isAdmin(user) && ( <>
{!!expiryDate && ( moment(date).isAfter(new Date())} dateFormat="dd/MM/yyyy" selected={expiryDate ? moment(expiryDate).toDate() : null} onChange={(date) => setExpiryDate(date)} /> )} {!expiryDate && (
Unlimited
)} setExpiryDate(checked ? entity.expiryDate || new Date() : null)} > Enable expiry date
setPaymentPrice(e ? parseInt(e) : undefined)} type="number" defaultValue={entity.payment?.price || 0} thin />