Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/components/layouts/buttons/QuickActionsButton.tsx
T

91 lines
3.8 KiB
TypeScript

import { Link, useParams } from "react-router";
import { useTranslation } from "react-i18next";
import { Transition } from "@headlessui/react";
import { Fragment, useState } from "react";
import { useOuterClick } from "~/utils/shared/KeypressUtils";
import { useAppData } from "~/utils/data/useAppData";
import UrlUtils from "~/utils/app/UrlUtils";
import { EntitySimple } from "~/utils/db/entities/entities.db.server";
import { getEntityPermission, getUserHasPermission } from "~/utils/helpers/PermissionsHelper";
import { PlusIcon } from "~/components/ui/icons/vendor";
interface Props {
entities: EntitySimple[];
className?: string;
}
export function quickActionEntityPath(params: { tenant?: string; group?: string }, entitySlug: string) {
const path = params.group ? `g/${params.group}/${entitySlug}/new` : `${entitySlug}/new`;
return UrlUtils.currentTenantUrl(params, path);
}
export default function QuickActionsButton({ entities, className }: Props) {
const { t } = useTranslation();
const params = useParams();
const appData = useAppData();
const [opened, setOpened] = useState(false);
const creatableEntities = entities.filter((entity) => getUserHasPermission(appData, getEntityPermission(entity, "create")));
const hasQuickActions = creatableEntities.length > 0;
const clickOutside = useOuterClick(() => setOpened(false));
return (
<span className={className} ref={clickOutside}>
{hasQuickActions && (
<div className="relative">
<div className="inline-flex divide-x divide-gray-300 rounded-sm shadow-none">
<div className="relative z-0 inline-flex rounded-full text-sm shadow-none">
<button
onClick={() => setOpened(!opened)}
type="button"
className="text-muted-foreground bg-secondary hover:bg-secondary/90 border-border relative inline-flex items-center rounded-full border p-2 font-medium shadow-inner focus:z-10 focus:outline-hidden focus:ring-2 focus:ring-offset-2"
aria-haspopup="listbox"
aria-expanded="true"
aria-label={t("shared.new")}
>
<span className="sr-only">{t("shared.new")}</span>
<PlusIcon className="h-5 w-5" />
</button>
</div>
</div>
<Transition
as={Fragment}
show={opened}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<ul
className="divide-border bg-background absolute right-0 z-40 mt-2 w-72 origin-top-right divide-y overflow-hidden rounded-sm shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-hidden"
tabIndex={-1}
aria-labelledby="listbox-label"
>
{creatableEntities.map((entity) => {
return (
<li key={entity.name} className="text-foreground relative cursor-default select-none text-sm" id="listbox-option-0">
<Link
to={quickActionEntityPath(params, entity.slug)}
onClick={() => setOpened(false)}
className="hover:bg-secondary flex flex-col p-4"
>
<div className="flex justify-between">
<p className="font-semibold">
{t("shared.new")} {t(entity.title)}
</p>
</div>
</Link>
</li>
);
})}
</ul>
</Transition>
</div>
)}
</span>
);
}