import { zodResolver } from "@hookform/resolvers/zod" import { HttpTypes } from "@medusajs/types" import { Button, createDataTableColumnHelper, DataTableRowSelectionState, Heading, Input, ProgressStatus, ProgressTabs, Text, Textarea, toast, } from "@medusajs/ui" import { keepPreviousData } from "@tanstack/react-query" import { useCallback, useEffect, useMemo, useState } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import { z } from "zod" import { DataTable } from "../../../../../components/data-table" import { Form } from "../../../../../components/common/form" import { RouteFocusModal, useRouteModal, } from "../../../../../components/modals" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { useRbacAssignablePolicies } from "../../../../../hooks/api/rbac-policies" import { useCreateRbacRole } from "../../../../../hooks/api/rbac-roles" import { useDocumentDirection } from "../../../../../hooks/use-document-direction" import { useQueryParams } from "../../../../../hooks/use-query-params" enum Tab { DETAILS = "details", PERMISSIONS = "permissions", } type TabState = Record const CreateRoleDetailsSchema = z.object({ name: z.string().min(1), description: z.string().optional(), }) const CreateRoleSchema = CreateRoleDetailsSchema.extend({ policies: z.array(z.string()).optional(), }) const PAGE_SIZE = 20 const PREFIX = "rp" const columnHelper = createDataTableColumnHelper< HttpTypes.AdminRbacAssignablePoliciesListResponse["policies"][number] >() export const CreateRoleForm = () => { const { t } = useTranslation() const { handleSuccess } = useRouteModal() const direction = useDocumentDirection() const [tab, setTab] = useState(Tab.DETAILS) const [tabState, setTabState] = useState({ [Tab.DETAILS]: "in-progress", [Tab.PERMISSIONS]: "not-started", }) const [rowSelection, setRowSelection] = useState( {} ) const form = useForm>({ defaultValues: { name: "", description: "", policies: [], }, resolver: zodResolver(CreateRoleSchema), }) const handleTabChange = async (nextTab: Tab) => { const valid = await form.trigger() if (!valid) { return } setTab(nextTab) } const { mutateAsync: createRole, isPending: isCreating } = useCreateRbacRole() const onRowSelectionChange = useCallback( (selection: DataTableRowSelectionState) => { const ids = Object.keys(selection).filter((id) => selection[id]) form.setValue("policies", ids, { shouldDirty: true, shouldTouch: true, }) setRowSelection(selection) }, [form] ) const { q, order, offset } = useQueryParams(["q", "order", "offset"], PREFIX) const { data: pageData, isPending: isPoliciesLoading, isError: isPoliciesError, error: policiesError, } = useRbacAssignablePolicies( { q, order, offset: offset ? parseInt(offset) : 0, limit: PAGE_SIZE, fields: "id,key,resource,operation,description", }, { placeholderData: keepPreviousData, } ) if (isPoliciesError) { throw policiesError } const visiblePolicies = pageData?.policies ?? [] const count = pageData?.count ?? 0 const columns = usePolicyColumns() const onNext = async (currentTab: Tab) => { const valid = await form.trigger() if (!valid) { return } if (currentTab === Tab.DETAILS) { setTab(Tab.PERMISSIONS) } } useEffect(() => { const currentState = { ...tabState } currentState[Tab.DETAILS] = tab === Tab.DETAILS ? "in-progress" : "completed" currentState[Tab.PERMISSIONS] = tab === Tab.DETAILS ? "not-started" : "in-progress" setTabState({ ...currentState }) // eslint-disable-next-line react-hooks/exhaustive-deps -- only update when tab changes }, [tab]) const handleSubmit = form.handleSubmit(async (values) => { try { const { role } = await createRole({ name: values.name.trim(), description: values.description?.trim() || null, policy_ids: values.policies?.length ? values.policies : undefined, }) toast.success( t("roles.create.successToast", { name: role.name, }) ) handleSuccess(`/settings/roles/${role.id}`) } catch (error) { toast.error((error as Error).message) } }) return ( handleTabChange(tab as Tab)} className="flex h-full flex-col overflow-hidden" >
{t("roles.create.tabs.details")} {t("roles.create.tabs.permissions")}
{t("roles.create.header")} {t("roles.create.hint")}
{ return ( {t("fields.name")} ) }} /> { return ( {t("fields.description")}