@better-auth-ui/heroui 1.6.9 → 1.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/auth/additional-field.d.ts +2 -2
- package/dist/components/auth/api-key/api-key.d.ts +1 -1
- package/dist/components/auth/api-key/api-keys.d.ts +1 -1
- package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +1 -1
- package/dist/components/auth/api-key/organization-api-keys.d.ts +1 -1
- package/dist/components/auth/auth-provider.d.ts +1 -1
- package/dist/components/auth/auth.d.ts +3 -3
- package/dist/components/auth/delete-user/danger-zone.d.ts +2 -2
- package/dist/components/auth/delete-user/delete-account.d.ts +1 -1
- package/dist/components/auth/email/email-changed-email.d.ts +2 -2
- package/dist/components/auth/email/email-verification-email.d.ts +2 -2
- package/dist/components/auth/email/magic-link-email.d.ts +2 -2
- package/dist/components/auth/email/new-device-email.d.ts +2 -2
- package/dist/components/auth/email/organization-invitation-email.d.ts +2 -2
- package/dist/components/auth/email/otp-email.d.ts +2 -2
- package/dist/components/auth/email/password-changed-email.d.ts +2 -2
- package/dist/components/auth/email/reset-password-email.d.ts +2 -2
- package/dist/components/auth/field-separator.d.ts +1 -1
- package/dist/components/auth/forgot-password.d.ts +1 -1
- package/dist/components/auth/magic-link/magic-link-button.d.ts +1 -1
- package/dist/components/auth/magic-link/magic-link.d.ts +2 -2
- package/dist/components/auth/multi-session/manage-account.d.ts +1 -1
- package/dist/components/auth/multi-session/manage-accounts.d.ts +1 -1
- package/dist/components/auth/multi-session/switch-account-submenu-item.d.ts +1 -1
- package/dist/components/auth/organization/delete-organization-dialog.d.ts +1 -1
- package/dist/components/auth/organization/leave-organization-dialog.d.ts +1 -1
- package/dist/components/auth/organization/organization-danger-zone.d.ts +2 -2
- package/dist/components/auth/organization/organization-invitation-row.d.ts +1 -1
- package/dist/components/auth/organization/organization-invitations.d.ts +1 -1
- package/dist/components/auth/organization/organization-logo.d.ts +3 -3
- package/dist/components/auth/organization/organization-member-row.d.ts +1 -1
- package/dist/components/auth/organization/organization-members.d.ts +1 -1
- package/dist/components/auth/organization/organization-people.d.ts +1 -1
- package/dist/components/auth/organization/organization-profile.d.ts +1 -1
- package/dist/components/auth/organization/organization-row.d.ts +1 -1
- package/dist/components/auth/organization/organization-settings.d.ts +2 -2
- package/dist/components/auth/organization/organization-switcher.d.ts +3 -3
- package/dist/components/auth/organization/organization-view-skeleton.d.ts +2 -2
- package/dist/components/auth/organization/organization-view.d.ts +3 -3
- package/dist/components/auth/organization/organization.d.ts +3 -3
- package/dist/components/auth/organization/organizations-settings.d.ts +2 -2
- package/dist/components/auth/organization/organizations.d.ts +1 -1
- package/dist/components/auth/organization/remove-member-dialog.d.ts +1 -1
- package/dist/components/auth/organization/slug-field.d.ts +1 -1
- package/dist/components/auth/organization/user-invitation-row.d.ts +1 -1
- package/dist/components/auth/organization/user-invitations.d.ts +1 -1
- package/dist/components/auth/passkey/passkey-button.d.ts +1 -1
- package/dist/components/auth/passkey/passkey.d.ts +1 -1
- package/dist/components/auth/passkey/passkeys.d.ts +1 -1
- package/dist/components/auth/provider-button.d.ts +2 -2
- package/dist/components/auth/reset-password.d.ts +1 -1
- package/dist/components/auth/settings/account/account-settings.d.ts +2 -2
- package/dist/components/auth/settings/account/change-email.d.ts +1 -1
- package/dist/components/auth/settings/account/user-profile.d.ts +1 -1
- package/dist/components/auth/settings/security/active-session.d.ts +1 -1
- package/dist/components/auth/settings/security/active-sessions.d.ts +1 -1
- package/dist/components/auth/settings/security/change-password.d.ts +1 -1
- package/dist/components/auth/settings/security/linked-account.d.ts +1 -1
- package/dist/components/auth/settings/security/linked-accounts.d.ts +1 -1
- package/dist/components/auth/settings/security/security-settings.d.ts +2 -2
- package/dist/components/auth/settings/settings.d.ts +3 -3
- package/dist/components/auth/sign-in.d.ts +2 -2
- package/dist/components/auth/sign-up.d.ts +2 -2
- package/dist/components/auth/theme/appearance.d.ts +1 -1
- package/dist/components/auth/user/user-avatar.d.ts +3 -3
- package/dist/components/auth/user/user-button.d.ts +2 -2
- package/dist/components/auth/user/user-view.d.ts +3 -3
- package/dist/components/auth/username/sign-in-username.d.ts +2 -2
- package/dist/components/auth/username/username-field.d.ts +1 -1
- package/dist/email.d.ts +8 -8
- package/dist/email.js +211 -8
- package/dist/index.d.ts +21 -21
- package/dist/index.js +1682 -21
- package/dist/lib/auth/api-key-plugin.d.ts +3 -3
- package/dist/lib/auth/auth-plugin.d.ts +5 -5
- package/dist/lib/auth/delete-user-plugin.d.ts +2 -2
- package/dist/lib/auth/magic-link-plugin.d.ts +3 -3
- package/dist/lib/auth/multi-session-plugin.d.ts +3 -3
- package/dist/lib/auth/organization-plugin.d.ts +2 -2
- package/dist/lib/auth/passkey-plugin.d.ts +3 -3
- package/dist/lib/auth/theme-plugin.d.ts +3 -3
- package/dist/lib/auth/username-plugin.d.ts +3 -3
- package/dist/plugins.d.ts +46 -46
- package/dist/plugins.js +2824 -47
- package/dist/user-view--47tVtJ3.js +113 -0
- package/package.json +2 -3
- package/dist/components/auth/additional-field.js +0 -137
- package/dist/components/auth/api-key/api-key-skeleton.js +0 -5
- package/dist/components/auth/api-key/api-key.js +0 -17
- package/dist/components/auth/api-key/api-keys-empty.js +0 -9
- package/dist/components/auth/api-key/api-keys.js +0 -22
- package/dist/components/auth/api-key/create-api-key-dialog.js +0 -44
- package/dist/components/auth/api-key/delete-api-key-dialog.js +0 -17
- package/dist/components/auth/api-key/new-api-key-dialog.js +0 -24
- package/dist/components/auth/api-key/organization-api-keys.js +0 -22
- package/dist/components/auth/auth-provider.js +0 -11
- package/dist/components/auth/auth.js +0 -88
- package/dist/components/auth/delete-user/danger-zone.js +0 -12
- package/dist/components/auth/delete-user/delete-account.js +0 -50
- package/dist/components/auth/email/email-changed-email.js +0 -23
- package/dist/components/auth/email/email-verification-email.js +0 -23
- package/dist/components/auth/email/magic-link-email.js +0 -23
- package/dist/components/auth/email/new-device-email.js +0 -23
- package/dist/components/auth/email/organization-invitation-email.js +0 -23
- package/dist/components/auth/email/otp-email.js +0 -22
- package/dist/components/auth/email/password-changed-email.js +0 -23
- package/dist/components/auth/email/reset-password-email.js +0 -23
- package/dist/components/auth/error-toaster.js +0 -33
- package/dist/components/auth/field-separator.js +0 -5
- package/dist/components/auth/forgot-password.js +0 -37
- package/dist/components/auth/magic-link/magic-link-button.js +0 -34
- package/dist/components/auth/magic-link/magic-link.js +0 -40
- package/dist/components/auth/multi-session/manage-account.js +0 -33
- package/dist/components/auth/multi-session/manage-accounts.js +0 -33
- package/dist/components/auth/multi-session/switch-account-submenu-content.js +0 -25
- package/dist/components/auth/multi-session/switch-account-submenu-item.js +0 -17
- package/dist/components/auth/multi-session/switch-account-submenu.js +0 -24
- package/dist/components/auth/organization/change-organization-logo.js +0 -69
- package/dist/components/auth/organization/create-organization-dialog.js +0 -37
- package/dist/components/auth/organization/delete-organization-dialog.js +0 -25
- package/dist/components/auth/organization/delete-organization-skeleton.js +0 -8
- package/dist/components/auth/organization/delete-organization.js +0 -27
- package/dist/components/auth/organization/invite-member-dialog.js +0 -47
- package/dist/components/auth/organization/leave-organization-dialog.js +0 -21
- package/dist/components/auth/organization/leave-organization.js +0 -16
- package/dist/components/auth/organization/organization-danger-zone.js +0 -23
- package/dist/components/auth/organization/organization-invitation-row-skeleton.js +0 -9
- package/dist/components/auth/organization/organization-invitation-row.js +0 -31
- package/dist/components/auth/organization/organization-invitations-empty.js +0 -13
- package/dist/components/auth/organization/organization-invitations.js +0 -66
- package/dist/components/auth/organization/organization-logo.js +0 -14
- package/dist/components/auth/organization/organization-member-row-skeleton.js +0 -9
- package/dist/components/auth/organization/organization-member-row.js +0 -34
- package/dist/components/auth/organization/organization-members.js +0 -67
- package/dist/components/auth/organization/organization-people.js +0 -11
- package/dist/components/auth/organization/organization-profile.js +0 -34
- package/dist/components/auth/organization/organization-row.js +0 -31
- package/dist/components/auth/organization/organization-settings.js +0 -13
- package/dist/components/auth/organization/organization-switcher.js +0 -48
- package/dist/components/auth/organization/organization-view-skeleton.js +0 -9
- package/dist/components/auth/organization/organization-view.js +0 -31
- package/dist/components/auth/organization/organization.js +0 -60
- package/dist/components/auth/organization/organizations-empty.js +0 -9
- package/dist/components/auth/organization/organizations-settings.js +0 -17
- package/dist/components/auth/organization/organizations.js +0 -21
- package/dist/components/auth/organization/remove-member-dialog.js +0 -20
- package/dist/components/auth/organization/slug-field.js +0 -38
- package/dist/components/auth/organization/user-invitation-row-skeleton.js +0 -8
- package/dist/components/auth/organization/user-invitation-row.js +0 -22
- package/dist/components/auth/organization/user-invitations-empty.js +0 -12
- package/dist/components/auth/organization/user-invitations.js +0 -18
- package/dist/components/auth/passkey/add-passkey-dialog.js +0 -22
- package/dist/components/auth/passkey/delete-passkey-dialog.js +0 -14
- package/dist/components/auth/passkey/passkey-button.js +0 -25
- package/dist/components/auth/passkey/passkey-skeleton.js +0 -5
- package/dist/components/auth/passkey/passkey.js +0 -17
- package/dist/components/auth/passkey/passkeys-empty.js +0 -9
- package/dist/components/auth/passkey/passkeys.js +0 -16
- package/dist/components/auth/provider-button.js +0 -29
- package/dist/components/auth/provider-buttons.js +0 -29
- package/dist/components/auth/reset-password.js +0 -57
- package/dist/components/auth/settings/account/account-settings.js +0 -22
- package/dist/components/auth/settings/account/change-avatar.js +0 -54
- package/dist/components/auth/settings/account/change-email.js +0 -28
- package/dist/components/auth/settings/account/user-profile.js +0 -65
- package/dist/components/auth/settings/security/active-session.js +0 -52
- package/dist/components/auth/settings/security/active-sessions.js +0 -23
- package/dist/components/auth/settings/security/change-password.js +0 -79
- package/dist/components/auth/settings/security/linked-account.js +0 -38
- package/dist/components/auth/settings/security/linked-accounts.js +0 -36
- package/dist/components/auth/settings/security/security-settings.js +0 -20
- package/dist/components/auth/settings/settings.js +0 -53
- package/dist/components/auth/sign-in.js +0 -64
- package/dist/components/auth/sign-out.js +0 -33
- package/dist/components/auth/sign-up.js +0 -98
- package/dist/components/auth/theme/appearance.js +0 -24
- package/dist/components/auth/theme/theme-toggle-item.js +0 -57
- package/dist/components/auth/user/user-avatar.js +0 -32
- package/dist/components/auth/user/user-button.js +0 -40
- package/dist/components/auth/user/user-view.js +0 -27
- package/dist/components/auth/username/sign-in-username.js +0 -88
- package/dist/components/auth/username/username-field.js +0 -45
- package/dist/lib/auth/api-key-plugin.js +0 -12
- package/dist/lib/auth/auth-plugin.js +0 -1
- package/dist/lib/auth/delete-user-plugin.js +0 -7
- package/dist/lib/auth/magic-link-plugin.js +0 -18
- package/dist/lib/auth/multi-session-plugin.js +0 -9
- package/dist/lib/auth/organization-plugin.js +0 -19
- package/dist/lib/auth/passkey-plugin.js +0 -9
- package/dist/lib/auth/theme-plugin.js +0 -26
- package/dist/lib/auth/username-plugin.js +0 -19
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Skeleton } from "@heroui/react";
|
|
3
|
-
/**
|
|
4
|
-
* Placeholder matching {@link DeleteOrganization} while the delete permission resolves.
|
|
5
|
-
*/
|
|
6
|
-
export function DeleteOrganizationSkeleton() {
|
|
7
|
-
return (_jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-3.5 w-40 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-64 rounded-lg" })] }), _jsx(Skeleton, { className: "h-8 w-36 shrink-0 rounded-full" })] }));
|
|
8
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useActiveOrganization, useAuth, useAuthPlugin, useHasPermission } from "@better-auth-ui/react";
|
|
3
|
-
import { AlertDialog, Button } from "@heroui/react";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
import { DeleteOrganizationDialog } from "./delete-organization-dialog";
|
|
7
|
-
import { DeleteOrganizationSkeleton } from "./delete-organization-skeleton";
|
|
8
|
-
/**
|
|
9
|
-
* Danger-zone row to delete the active organization. Hidden for members without
|
|
10
|
-
* the `organization:delete` permission.
|
|
11
|
-
*/
|
|
12
|
-
export function DeleteOrganization() {
|
|
13
|
-
const { authClient } = useAuth();
|
|
14
|
-
const { localization: organizationLocalization } = useAuthPlugin(organizationPlugin);
|
|
15
|
-
const { data: activeOrganization } = useActiveOrganization(authClient);
|
|
16
|
-
const { data: permission, isPending: permissionPending } = useHasPermission(authClient, {
|
|
17
|
-
permissions: { organization: ["delete"] }
|
|
18
|
-
});
|
|
19
|
-
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
20
|
-
if (permissionPending) {
|
|
21
|
-
return _jsx(DeleteOrganizationSkeleton, {});
|
|
22
|
-
}
|
|
23
|
-
if (!permission?.success) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
return (_jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium leading-tight", children: organizationLocalization.deleteOrganization }), _jsx("p", { className: "text-muted mt-0.5 text-xs", children: organizationLocalization.deleteOrganizationDescription })] }), _jsxs(AlertDialog, { children: [_jsx(Button, { isDisabled: !activeOrganization, size: "sm", variant: "danger-soft", onPress: () => setConfirmOpen(true), children: organizationLocalization.deleteOrganization }), activeOrganization && (_jsx(DeleteOrganizationDialog, { isOpen: confirmOpen, onOpenChange: setConfirmOpen, organization: activeOrganization }))] })] }));
|
|
27
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthPlugin, useInviteMember } from "@better-auth-ui/react";
|
|
3
|
-
import { PersonPlus } from "@gravity-ui/icons";
|
|
4
|
-
import { AlertDialog, Button, FieldError, Form, Input, Label, ListBox, Select, Spinner, TextField, toast } from "@heroui/react";
|
|
5
|
-
import { useEffect, useState } from "react";
|
|
6
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
7
|
-
const pickDefaultRole = (keys) => keys.includes("member") ? "member" : (keys.at(-1) ?? "");
|
|
8
|
-
/**
|
|
9
|
-
* Render a dialog for inviting a member to the organization.
|
|
10
|
-
*
|
|
11
|
-
* @param isOpen - Whether the dialog is open
|
|
12
|
-
* @param onOpenChange - Callback for when the dialog open state changes
|
|
13
|
-
* @returns The invite member dialog as a JSX element
|
|
14
|
-
*/
|
|
15
|
-
export function InviteMemberDialog({ isOpen, onOpenChange }) {
|
|
16
|
-
const { authClient, localization } = useAuth();
|
|
17
|
-
const { localization: organizationLocalization, roles } = useAuthPlugin(organizationPlugin);
|
|
18
|
-
const [role, setRole] = useState(() => pickDefaultRole(Object.keys(roles)));
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
setRole((current) => {
|
|
21
|
-
const keys = Object.keys(roles);
|
|
22
|
-
return keys.includes(current) ? current : pickDefaultRole(keys);
|
|
23
|
-
});
|
|
24
|
-
}, [roles]);
|
|
25
|
-
const { mutate: inviteMember, isPending: isInviting } = useInviteMember(authClient, {
|
|
26
|
-
onSuccess: () => {
|
|
27
|
-
onOpenChange(false);
|
|
28
|
-
toast.success(organizationLocalization.inviteMemberSuccess);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
const isRoleValid = Object.keys(roles).includes(role);
|
|
32
|
-
const handleSubmit = (e) => {
|
|
33
|
-
e.preventDefault();
|
|
34
|
-
if (!isRoleValid)
|
|
35
|
-
return;
|
|
36
|
-
const formData = new FormData(e.target);
|
|
37
|
-
const email = formData.get("email");
|
|
38
|
-
inviteMember({
|
|
39
|
-
email: email.trim(),
|
|
40
|
-
role: role
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
return (_jsx(AlertDialog.Backdrop, { isOpen: isOpen, onOpenChange: onOpenChange, children: _jsx(AlertDialog.Container, { children: _jsx(AlertDialog.Dialog, { children: _jsxs(Form, { onSubmit: handleSubmit, children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "default", children: _jsx(PersonPlus, {}) }), _jsx(AlertDialog.Heading, { children: organizationLocalization.inviteMember })] }), _jsxs(AlertDialog.Body, { className: "flex flex-col gap-4 overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: organizationLocalization.inviteMemberDescription }), _jsxs(TextField, { id: "email", name: "email", type: "email", isDisabled: isInviting, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { autoFocus: true, placeholder: localization.auth.email, variant: "secondary", required: true }), _jsx(FieldError, {})] }), _jsxs(Select, { name: "role", value: role, onChange: (value) => {
|
|
44
|
-
if (typeof value === "string")
|
|
45
|
-
setRole(value);
|
|
46
|
-
}, isDisabled: isInviting, variant: "secondary", fullWidth: true, children: [_jsx(Label, { children: organizationLocalization.role }), _jsxs(Select.Trigger, { children: [_jsx(Select.Value, {}), _jsx(Select.Indicator, {})] }), _jsx(Select.Popover, { children: _jsx(ListBox, { children: Object.entries(roles).map(([key, label]) => (_jsxs(ListBox.Item, { id: key, textValue: label, children: [label, _jsx(ListBox.ItemIndicator, {})] }, key))) }) }), _jsx(FieldError, {})] })] }), _jsxs(AlertDialog.Footer, { children: [_jsx(Button, { slot: "close", variant: "tertiary", isDisabled: isInviting, children: localization.settings.cancel }), _jsxs(Button, { type: "submit", isPending: isInviting, isDisabled: !isRoleValid, children: [isInviting && _jsx(Spinner, { color: "current", size: "sm" }), organizationLocalization.inviteMember] })] })] }) }) }) }));
|
|
47
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthPlugin, useLeaveOrganization } from "@better-auth-ui/react";
|
|
3
|
-
import { ArrowRightFromSquare } from "@gravity-ui/icons";
|
|
4
|
-
import { AlertDialog, Button, Card, Spinner, toast } from "@heroui/react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
import { OrganizationView } from "./organization-view";
|
|
7
|
-
export function LeaveOrganizationDialog({ isOpen, onOpenChange, organization }) {
|
|
8
|
-
const { authClient, basePaths, localization, navigate } = useAuth();
|
|
9
|
-
const { localization: organizationLocalization, viewPaths: organizationPluginViewPaths } = useAuthPlugin(organizationPlugin);
|
|
10
|
-
const { mutate: leaveOrganization, isPending } = useLeaveOrganization(authClient, {
|
|
11
|
-
onSuccess: () => {
|
|
12
|
-
onOpenChange(false);
|
|
13
|
-
toast.success(organizationLocalization.leftOrganization);
|
|
14
|
-
navigate({
|
|
15
|
-
to: `${basePaths.settings}/${organizationPluginViewPaths.settings.organizations}`,
|
|
16
|
-
replace: true
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
return (_jsx(AlertDialog.Backdrop, { isOpen: isOpen, onOpenChange: onOpenChange, children: _jsx(AlertDialog.Container, { children: _jsxs(AlertDialog.Dialog, { children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "danger", children: _jsx(ArrowRightFromSquare, {}) }), _jsx(AlertDialog.Heading, { children: organizationLocalization.leaveOrganization })] }), _jsxs(AlertDialog.Body, { className: "flex flex-col gap-4 overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: organizationLocalization.leaveOrganizationDescription }), _jsx(Card, { variant: "secondary", children: _jsx(Card.Content, { children: _jsx(OrganizationView, { organization: organization, hideRole: true }) }) })] }), _jsxs(AlertDialog.Footer, { children: [_jsx(Button, { slot: "close", variant: "tertiary", isDisabled: isPending, children: localization.settings.cancel }), _jsxs(Button, { variant: "danger", isPending: isPending, onPress: () => leaveOrganization({ organizationId: organization.id }), children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), organizationLocalization.leaveOrganization] })] })] }) }) }));
|
|
21
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useActiveOrganization, useAuth, useAuthPlugin } from "@better-auth-ui/react";
|
|
3
|
-
import { AlertDialog, Button } from "@heroui/react";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
import { LeaveOrganizationDialog } from "./leave-organization-dialog";
|
|
7
|
-
/**
|
|
8
|
-
* Danger-zone row to leave the active organization.
|
|
9
|
-
*/
|
|
10
|
-
export function LeaveOrganization() {
|
|
11
|
-
const { authClient } = useAuth();
|
|
12
|
-
const { localization: organizationLocalization } = useAuthPlugin(organizationPlugin);
|
|
13
|
-
const { data: activeOrganization } = useActiveOrganization(authClient);
|
|
14
|
-
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
15
|
-
return (_jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium leading-tight", children: organizationLocalization.leaveOrganization }), _jsx("p", { className: "text-muted mt-0.5 text-xs", children: organizationLocalization.leaveOrganizationDescription })] }), _jsxs(AlertDialog, { children: [_jsx(Button, { isDisabled: !activeOrganization, size: "sm", variant: "danger-soft", onPress: () => setConfirmOpen(true), children: organizationLocalization.leaveOrganization }), activeOrganization && (_jsx(LeaveOrganizationDialog, { isOpen: confirmOpen, onOpenChange: setConfirmOpen, organization: activeOrganization }))] })] }));
|
|
16
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useHasPermission } from "@better-auth-ui/react";
|
|
3
|
-
import { Card, cn } from "@heroui/react";
|
|
4
|
-
import { DeleteOrganization } from "./delete-organization";
|
|
5
|
-
import { DeleteOrganizationSkeleton } from "./delete-organization-skeleton";
|
|
6
|
-
import { LeaveOrganization } from "./leave-organization";
|
|
7
|
-
/**
|
|
8
|
-
* Danger zone heading with {@link LeaveOrganization} and {@link DeleteOrganization}
|
|
9
|
-
* for the active organization in a single card.
|
|
10
|
-
*
|
|
11
|
-
* Resolves the `organization:delete` permission before rendering anything to
|
|
12
|
-
* avoid flashing {@link LeaveOrganization} (and a stray separator) before the
|
|
13
|
-
* delete row appears or disappears. Inner {@link DeleteOrganization} also
|
|
14
|
-
* self-gates so it stays safe to use standalone.
|
|
15
|
-
*/
|
|
16
|
-
export function OrganizationDangerZone({ className, variant, ...props }) {
|
|
17
|
-
const { authClient, localization } = useAuth();
|
|
18
|
-
const { data: deletePermission, isPending: deletePermissionPending } = useHasPermission(authClient, {
|
|
19
|
-
permissions: { organization: ["delete"] }
|
|
20
|
-
});
|
|
21
|
-
const canDelete = !!deletePermission?.success;
|
|
22
|
-
return (_jsxs("div", { className: cn("flex w-full flex-col", className), ...props, children: [_jsx("h2", { className: cn("mb-3 text-sm font-semibold text-danger"), children: localization.settings.dangerZone }), _jsx(Card, { variant: variant, children: _jsx(Card.Content, { className: "gap-0", children: deletePermissionPending ? (_jsx(DeleteOrganizationSkeleton, {})) : (_jsxs(_Fragment, { children: [_jsx(LeaveOrganization, {}), canDelete && (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-b border-dashed -mx-4 my-4" }), _jsx(DeleteOrganization, {})] }))] })) }) })] }));
|
|
23
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Skeleton, Table } from "@heroui/react";
|
|
3
|
-
/**
|
|
4
|
-
* Placeholder row matching {@link OrganizationInvitationTableRow} while
|
|
5
|
-
* invitations load.
|
|
6
|
-
*/
|
|
7
|
-
export function OrganizationInvitationRowSkeleton() {
|
|
8
|
-
return (_jsxs(Table.Row, { children: [_jsx(Table.Cell, { children: _jsx(Skeleton, { className: "h-4 w-48 rounded-lg" }) }), _jsx(Table.Cell, { children: _jsx(Skeleton, { className: "h-4 w-36 rounded-lg" }) }), _jsx(Table.Cell, { children: _jsx(Skeleton, { className: "h-4 w-16 rounded-lg" }) }), _jsx(Table.Cell, { children: _jsx(Skeleton, { className: "h-4 w-14 rounded-full" }) }), _jsx(Table.Cell, {})] }));
|
|
9
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthPlugin, useCancelInvitation, useHasPermission } from "@better-auth-ui/react";
|
|
3
|
-
import { Xmark } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Chip, Spinner, Table } from "@heroui/react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
import { OrganizationInvitationRowSkeleton } from "./organization-invitation-row-skeleton";
|
|
7
|
-
export function OrganizationInvitationTableRow({ invitation }) {
|
|
8
|
-
const { authClient } = useAuth();
|
|
9
|
-
const { localization: organizationLocalization, roles } = useAuthPlugin(organizationPlugin);
|
|
10
|
-
const { data: cancelInvitationPermission, isPending: cancelPermissionPending } = useHasPermission(authClient, {
|
|
11
|
-
permissions: { invitation: ["cancel"] }
|
|
12
|
-
});
|
|
13
|
-
const { mutate: cancelInvitation, isPending: cancelPending } = useCancelInvitation(authClient);
|
|
14
|
-
const roleLabel = roles?.[invitation.role] ?? invitation.role;
|
|
15
|
-
const statusLabel = organizationLocalization[invitation.status] ?? invitation.status;
|
|
16
|
-
const statusColor = invitation.status === "pending"
|
|
17
|
-
? "warning"
|
|
18
|
-
: invitation.status === "accepted"
|
|
19
|
-
? "success"
|
|
20
|
-
: invitation.status === "rejected"
|
|
21
|
-
? "danger"
|
|
22
|
-
: "default";
|
|
23
|
-
if (cancelPermissionPending) {
|
|
24
|
-
return _jsx(OrganizationInvitationRowSkeleton, {});
|
|
25
|
-
}
|
|
26
|
-
return (_jsxs(Table.Row, { children: [_jsx(Table.Cell, { className: "font-medium text-sm", children: invitation.email }), _jsx(Table.Cell, { className: "text-muted text-xs tabular-nums whitespace-nowrap", children: new Date(invitation.createdAt).toLocaleString(undefined, {
|
|
27
|
-
dateStyle: "short",
|
|
28
|
-
timeStyle: "short"
|
|
29
|
-
}) }), _jsx(Table.Cell, { className: "text-sm", children: roleLabel }), _jsx(Table.Cell, { className: "text-sm", children: _jsx(Chip, { color: statusColor, size: "sm", variant: "soft", children: statusLabel }) }), _jsx(Table.Cell, { className: "text-end", children: cancelInvitationPermission?.success &&
|
|
30
|
-
invitation.status === "pending" && (_jsx(Button, { isIconOnly: true, size: "sm", variant: "danger-soft", isPending: cancelPending, onPress: () => cancelInvitation({ invitationId: invitation.id }), "aria-label": organizationLocalization.cancelInvitation, children: cancelPending ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(Xmark, {})) })) })] }));
|
|
31
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuthPlugin } from "@better-auth-ui/react";
|
|
3
|
-
import { PaperPlane } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, EmptyState } from "@heroui/react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
/**
|
|
7
|
-
* Empty state for {@link OrganizationInvitations} — mirrors `ApiKeysEmpty`
|
|
8
|
-
* (icon, title, description) with an "Invite member" call to action.
|
|
9
|
-
*/
|
|
10
|
-
export function OrganizationInvitationsEmpty({ onInvitePress }) {
|
|
11
|
-
const { localization: organizationLocalization } = useAuthPlugin(organizationPlugin);
|
|
12
|
-
return (_jsxs(EmptyState, { className: "flex flex-col items-center gap-4 text-center p-4", children: [_jsx(PaperPlane, { className: "size-6 text-muted" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("p", { className: "text-sm font-semibold text-foreground", children: organizationLocalization.noInvitations }), _jsx("span", { className: "text-sm text-muted", children: organizationLocalization.organizationInvitationsEmptyDescription })] }), _jsx(Button, { size: "sm", onPress: onInvitePress, children: organizationLocalization.inviteMember })] }));
|
|
13
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthPlugin, useHasPermission, useListOrganizationInvitations } from "@better-auth-ui/react";
|
|
3
|
-
import { ChevronUp, Funnel, Xmark } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Chip, cn, Dropdown, Label, SearchField, Table } from "@heroui/react";
|
|
5
|
-
import { useMemo, useState } from "react";
|
|
6
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
7
|
-
import { InviteMemberDialog } from "./invite-member-dialog";
|
|
8
|
-
import { OrganizationInvitationTableRow } from "./organization-invitation-row";
|
|
9
|
-
import { OrganizationInvitationRowSkeleton } from "./organization-invitation-row-skeleton";
|
|
10
|
-
import { OrganizationInvitationsEmpty } from "./organization-invitations-empty";
|
|
11
|
-
/**
|
|
12
|
-
* Organization invitations table with invite control and per-row actions.
|
|
13
|
-
*/
|
|
14
|
-
export function OrganizationInvitations({ className, ...props }) {
|
|
15
|
-
const { authClient, localization } = useAuth();
|
|
16
|
-
const { localization: organizationLocalization, roles } = useAuthPlugin(organizationPlugin);
|
|
17
|
-
const { data: invitations, isPending: invitationsPending } = useListOrganizationInvitations(authClient);
|
|
18
|
-
const { isPending: invitationPermissionPending } = useHasPermission(authClient, {
|
|
19
|
-
permissions: { invitation: ["cancel"] }
|
|
20
|
-
});
|
|
21
|
-
const isPending = invitationsPending || invitationPermissionPending;
|
|
22
|
-
const [sortDescriptor, setSortDescriptor] = useState();
|
|
23
|
-
const [roleFilter, setRoleFilter] = useState("all");
|
|
24
|
-
const [statusFilter, setStatusFilter] = useState("all");
|
|
25
|
-
const [search, setSearch] = useState("");
|
|
26
|
-
const filteredInvitations = useMemo(() => {
|
|
27
|
-
return invitations?.filter((invitation) => (roleFilter === "all" || invitation.role === roleFilter) &&
|
|
28
|
-
(statusFilter === "all" || invitation.status === statusFilter) &&
|
|
29
|
-
invitation.email.toLowerCase().includes(search.toLowerCase()));
|
|
30
|
-
}, [search, invitations, roleFilter, statusFilter]);
|
|
31
|
-
const sortedInvitations = useMemo(() => {
|
|
32
|
-
if (!sortDescriptor)
|
|
33
|
-
return filteredInvitations;
|
|
34
|
-
if (!filteredInvitations)
|
|
35
|
-
return filteredInvitations;
|
|
36
|
-
return [...filteredInvitations].sort((a, b) => {
|
|
37
|
-
const col = sortDescriptor.column;
|
|
38
|
-
let cmp = 0;
|
|
39
|
-
if (col === "createdAt") {
|
|
40
|
-
cmp = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
cmp = String(a[col]).localeCompare(String(b[col]));
|
|
44
|
-
}
|
|
45
|
-
if (sortDescriptor.direction === "descending") {
|
|
46
|
-
cmp *= -1;
|
|
47
|
-
}
|
|
48
|
-
return cmp;
|
|
49
|
-
});
|
|
50
|
-
}, [sortDescriptor, filteredInvitations]);
|
|
51
|
-
const [inviteOpen, setInviteOpen] = useState(false);
|
|
52
|
-
return (_jsxs("div", { className: cn("flex flex-col gap-3", className), ...props, children: [_jsx("h3", { className: "truncate text-sm font-semibold", children: organizationLocalization.invitations }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(SearchField, { className: "min-w-0", "aria-label": organizationLocalization.search, value: search, onChange: setSearch, isDisabled: isPending, children: _jsxs(SearchField.Group, { children: [_jsx(SearchField.SearchIcon, {}), _jsx(SearchField.Input, { placeholder: organizationLocalization.search, className: "sm:w-[200px]" }), _jsx(SearchField.ClearButton, {})] }) }), _jsxs(Dropdown, { children: [_jsxs(Button, { size: "sm", variant: "secondary", isDisabled: isPending, children: [_jsx(Funnel, {}), organizationLocalization.role] }), _jsx(Dropdown.Popover, { children: _jsxs(Dropdown.Menu, { selectionMode: "single", selectedKeys: new Set([roleFilter]), onSelectionChange: (keys) => {
|
|
53
|
-
const key = [...keys][0];
|
|
54
|
-
setRoleFilter(key ?? "all");
|
|
55
|
-
}, children: [_jsxs(Dropdown.Item, { id: "all", textValue: organizationLocalization.all, children: [_jsx(Label, { children: organizationLocalization.all }), _jsx(Dropdown.ItemIndicator, {})] }), Object.entries(roles).map(([key, label]) => (_jsxs(Dropdown.Item, { id: key, textValue: label, children: [_jsx(Label, { children: label }), _jsx(Dropdown.ItemIndicator, {})] }, key)))] }) })] }), _jsxs(Dropdown, { children: [_jsxs(Button, { size: "sm", variant: "secondary", isDisabled: isPending, children: [_jsx(Funnel, {}), organizationLocalization.status] }), _jsx(Dropdown.Popover, { children: _jsxs(Dropdown.Menu, { selectionMode: "single", selectedKeys: new Set([statusFilter]), onSelectionChange: (keys) => {
|
|
56
|
-
const key = [...keys][0];
|
|
57
|
-
setStatusFilter(key ?? "all");
|
|
58
|
-
}, children: [_jsxs(Dropdown.Item, { id: "all", textValue: organizationLocalization.all, children: [_jsx(Label, { children: organizationLocalization.all }), _jsx(Dropdown.ItemIndicator, {})] }), ["pending", "accepted", "rejected", "canceled"].map((status) => (_jsxs(Dropdown.Item, { id: status, textValue: organizationLocalization[status] ?? status, children: [_jsx(Label, { children: organizationLocalization[status] ?? status }), _jsx(Dropdown.ItemIndicator, {})] }, status)))] }) })] })] }), (roleFilter !== "all" || statusFilter !== "all") && (_jsxs("div", { className: "flex flex-wrap gap-2", children: [roleFilter !== "all" && (_jsxs(Chip, { size: "sm", variant: "secondary", className: "w-fit", children: [_jsxs(Chip.Label, { children: [organizationLocalization.role, ":", " ", _jsx("span", { className: "capitalize", children: roles?.[roleFilter] ?? roleFilter })] }), _jsx("button", { type: "button", "aria-label": organizationLocalization.clear, className: "text-muted hover:text-foreground inline-flex cursor-pointer items-center", onClick: () => setRoleFilter("all"), children: _jsx(Xmark, { className: "size-3" }) })] })), statusFilter !== "all" && (_jsxs(Chip, { size: "sm", variant: "secondary", className: "w-fit", children: [_jsxs(Chip.Label, { children: [organizationLocalization.status, ":", " ", organizationLocalization[statusFilter] ?? statusFilter] }), _jsx("button", { type: "button", "aria-label": organizationLocalization.clear, className: "text-muted hover:text-foreground inline-flex cursor-pointer items-center", onClick: () => setStatusFilter("all"), children: _jsx(Xmark, { className: "size-3" }) })] }))] })), _jsx(Table, { children: _jsx(Table.ScrollContainer, { children: _jsxs(Table.Content, { "aria-label": organizationLocalization.invitations, sortDescriptor: sortDescriptor, onSortChange: (descriptor) => {
|
|
59
|
-
const shouldReset = sortDescriptor?.column === descriptor.column &&
|
|
60
|
-
descriptor.direction === "ascending";
|
|
61
|
-
setSortDescriptor(shouldReset ? undefined : descriptor);
|
|
62
|
-
}, children: [_jsxs(Table.Header, { children: [_jsx(Table.Column, { allowsSorting: true, isRowHeader: true, id: "email", children: ({ sortDirection }) => (_jsx(SortableColumnHeader, { sortDirection: sortDirection, children: localization.auth.email })) }), _jsx(Table.Column, { allowsSorting: true, id: "createdAt", children: ({ sortDirection }) => (_jsx(SortableColumnHeader, { sortDirection: sortDirection, children: organizationLocalization.invitedAt })) }), _jsx(Table.Column, { allowsSorting: true, id: "role", children: ({ sortDirection }) => (_jsx(SortableColumnHeader, { sortDirection: sortDirection, children: organizationLocalization.role })) }), _jsx(Table.Column, { allowsSorting: true, id: "status", children: ({ sortDirection }) => (_jsx(SortableColumnHeader, { sortDirection: sortDirection, children: organizationLocalization.status })) }), _jsx(Table.Column, { className: "text-end", children: organizationLocalization.actions })] }), _jsx(Table.Body, { renderEmptyState: () => (_jsx(OrganizationInvitationsEmpty, { onInvitePress: () => setInviteOpen(true) })), children: isPending ? (_jsx(OrganizationInvitationRowSkeleton, {})) : (sortedInvitations?.map((invitation) => (_jsx(OrganizationInvitationTableRow, { invitation: invitation }, invitation.id)))) })] }) }) })] }), _jsx(InviteMemberDialog, { isOpen: inviteOpen, onOpenChange: setInviteOpen })] }));
|
|
63
|
-
}
|
|
64
|
-
function SortableColumnHeader({ children, sortDirection }) {
|
|
65
|
-
return (_jsxs("span", { className: "flex items-center justify-between", children: [children, !!sortDirection && (_jsx(ChevronUp, { className: cn("size-3 transform transition-transform duration-100 ease-out", sortDirection === "descending" ? "rotate-180" : "") }))] }));
|
|
66
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Briefcase } from "@gravity-ui/icons";
|
|
3
|
-
import { Avatar, cn, Skeleton } from "@heroui/react";
|
|
4
|
-
/**
|
|
5
|
-
* Renders an organization logo image, initials fallback, or a briefcase icon;
|
|
6
|
-
* shows a circular skeleton while loading when `isPending` is set and `organization` is undefined.
|
|
7
|
-
*/
|
|
8
|
-
export function OrganizationLogo({ className, fallback, isPending, organization, size = "sm", style, ...props }) {
|
|
9
|
-
if (isPending && !organization) {
|
|
10
|
-
return (_jsx(Skeleton, { className: cn("rounded-full", size === "sm" ? "size-8" : size === "md" ? "size-10" : "size-12", className), style: style }));
|
|
11
|
-
}
|
|
12
|
-
const initials = organization?.name?.slice(0, 2).toUpperCase();
|
|
13
|
-
return (_jsxs(Avatar, { size: size, className: cn("rounded-full", className), style: style, ...props, children: [_jsx(Avatar.Image, { alt: organization?.name ?? "Organization", src: organization?.logo ?? undefined }), _jsx(Avatar.Fallback, { className: cn(size === "lg" ? "text-xl" : size === "md" ? "text-base" : "text-sm"), delayMs: organization?.logo ? 600 : undefined, children: fallback || initials || _jsx(Briefcase, { className: "size-4" }) })] }));
|
|
14
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Skeleton, Table } from "@heroui/react";
|
|
3
|
-
import { UserView } from "../user/user-view";
|
|
4
|
-
/**
|
|
5
|
-
* Placeholder row matching {@link OrganizationMemberRow} while members load.
|
|
6
|
-
*/
|
|
7
|
-
export function OrganizationMemberRowSkeleton() {
|
|
8
|
-
return (_jsxs(Table.Row, { children: [_jsx(Table.Cell, { children: _jsx(UserView, { isPending: true }) }), _jsx(Table.Cell, { children: _jsx(Skeleton, { className: "h-4 w-18 rounded-lg" }) }), _jsx(Table.Cell, { className: "flex justify-end", children: _jsx(Skeleton, { className: "size-8 rounded-full" }) })] }));
|
|
9
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthPlugin, useHasPermission, useSession, useUpdateMemberRole } from "@better-auth-ui/react";
|
|
3
|
-
import { ArrowRightFromSquare, Pencil, TrashBin } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Dropdown, Label, Spinner, Table, toast } from "@heroui/react";
|
|
5
|
-
import { useState } from "react";
|
|
6
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
7
|
-
import { UserView } from "../user/user-view";
|
|
8
|
-
import { LeaveOrganizationDialog } from "./leave-organization-dialog";
|
|
9
|
-
import { OrganizationMemberRowSkeleton } from "./organization-member-row-skeleton";
|
|
10
|
-
import { RemoveMemberDialog } from "./remove-member-dialog";
|
|
11
|
-
export function OrganizationMemberRow({ member, isOwner, organization }) {
|
|
12
|
-
const { authClient } = useAuth();
|
|
13
|
-
const { localization: organizationLocalization, roles } = useAuthPlugin(organizationPlugin);
|
|
14
|
-
const { data: session } = useSession(authClient);
|
|
15
|
-
const { data: hasUpdatePermission, isPending: updatePermissionPending } = useHasPermission(authClient, {
|
|
16
|
-
permissions: { member: ["update"] }
|
|
17
|
-
});
|
|
18
|
-
const { data: hasDeletePermission, isPending: deletePermissionPending } = useHasPermission(authClient, {
|
|
19
|
-
permissions: { member: ["delete"] }
|
|
20
|
-
});
|
|
21
|
-
const isPending = updatePermissionPending || deletePermissionPending;
|
|
22
|
-
const { mutate: updateMemberRole, isPending: isUpdatingRole } = useUpdateMemberRole(authClient, {
|
|
23
|
-
onSuccess: () => toast.success(organizationLocalization.memberRoleUpdated)
|
|
24
|
-
});
|
|
25
|
-
const roleLabel = roles?.[member.role] ?? member.role;
|
|
26
|
-
const assignableRoles = Object.entries(roles).filter(([key]) => isOwner || key !== "owner");
|
|
27
|
-
const isCurrentUser = session?.user.id === member.userId;
|
|
28
|
-
const [removeOpen, setRemoveOpen] = useState(false);
|
|
29
|
-
const [leaveOpen, setLeaveOpen] = useState(false);
|
|
30
|
-
if (isPending) {
|
|
31
|
-
return _jsx(OrganizationMemberRowSkeleton, {});
|
|
32
|
-
}
|
|
33
|
-
return (_jsxs(Table.Row, { children: [_jsx(Table.Cell, { children: _jsx(UserView, { user: member.user }) }), _jsx(Table.Cell, { children: roleLabel }), _jsxs(Table.Cell, { children: [_jsxs("div", { className: "flex items-center justify-end gap-1", children: [hasUpdatePermission?.success && (_jsxs(Dropdown, { children: [_jsx(Button, { isIconOnly: true, size: "sm", variant: "tertiary", isDisabled: isUpdatingRole, "aria-label": organizationLocalization.changeMemberRole, children: isUpdatingRole ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(Pencil, {})) }), _jsx(Dropdown.Popover, { className: "min-w-fit", children: _jsx(Dropdown.Menu, { children: assignableRoles.map(([role, label]) => (_jsx(Dropdown.Item, { textValue: label, isDisabled: member.role === role, onAction: () => updateMemberRole({ memberId: member.id, role }), children: _jsx(Label, { children: label }) }, role))) }) })] })), isCurrentUser ? (_jsx(Button, { isIconOnly: true, size: "sm", variant: "danger-soft", "aria-label": organizationLocalization.leaveOrganization, onPress: () => setLeaveOpen(true), children: _jsx(ArrowRightFromSquare, {}) })) : (hasDeletePermission?.success && (_jsx(Button, { isIconOnly: true, size: "sm", variant: "danger-soft", "aria-label": organizationLocalization.removeMember, onPress: () => setRemoveOpen(true), children: _jsx(TrashBin, {}) })))] }), isCurrentUser && organization ? (_jsx(LeaveOrganizationDialog, { isOpen: leaveOpen, onOpenChange: setLeaveOpen, organization: organization })) : (hasDeletePermission?.success && (_jsx(RemoveMemberDialog, { isOpen: removeOpen, onOpenChange: setRemoveOpen, member: member })))] })] }));
|
|
34
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useActiveOrganization, useAuth, useAuthPlugin, useHasPermission, useListOrganizationMembers, useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { ChevronUp, Funnel, Xmark } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Chip, cn, Dropdown, Label, SearchField, Table } from "@heroui/react";
|
|
5
|
-
import { useMemo, useState } from "react";
|
|
6
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
7
|
-
import { InviteMemberDialog } from "./invite-member-dialog";
|
|
8
|
-
import { OrganizationMemberRow } from "./organization-member-row";
|
|
9
|
-
import { OrganizationMemberRowSkeleton } from "./organization-member-row-skeleton";
|
|
10
|
-
/**
|
|
11
|
-
* Organization members table with title, invite control, and per-row actions.
|
|
12
|
-
*/
|
|
13
|
-
export function OrganizationMembers({ className, ...props }) {
|
|
14
|
-
const { authClient } = useAuth();
|
|
15
|
-
const { localization: organizationLocalization, roles } = useAuthPlugin(organizationPlugin);
|
|
16
|
-
const { data: session } = useSession(authClient);
|
|
17
|
-
const { data: activeOrganization, isPending: activeOrganizationPending } = useActiveOrganization(authClient);
|
|
18
|
-
const { data: membersData, isPending: membersPending } = useListOrganizationMembers(authClient);
|
|
19
|
-
const { isPending: updatePermissionPending } = useHasPermission(authClient, {
|
|
20
|
-
permissions: { member: ["update"] }
|
|
21
|
-
});
|
|
22
|
-
const { isPending: deletePermissionPending } = useHasPermission(authClient, {
|
|
23
|
-
permissions: { member: ["delete"] }
|
|
24
|
-
});
|
|
25
|
-
const isPending = activeOrganizationPending ||
|
|
26
|
-
membersPending ||
|
|
27
|
-
updatePermissionPending ||
|
|
28
|
-
deletePermissionPending;
|
|
29
|
-
const [sortDescriptor, setSortDescriptor] = useState();
|
|
30
|
-
const [roleFilter, setRoleFilter] = useState("all");
|
|
31
|
-
const [search, setSearch] = useState("");
|
|
32
|
-
const filteredMembers = useMemo(() => {
|
|
33
|
-
return membersData?.members.filter((member) => (roleFilter === "all" || member.role === roleFilter) &&
|
|
34
|
-
(member.user.name.toLowerCase().includes(search.toLowerCase()) ||
|
|
35
|
-
member.user.email.toLowerCase().includes(search.toLowerCase())));
|
|
36
|
-
}, [search, membersData?.members, roleFilter]);
|
|
37
|
-
const sortedMembers = useMemo(() => {
|
|
38
|
-
if (!sortDescriptor)
|
|
39
|
-
return filteredMembers;
|
|
40
|
-
if (!filteredMembers)
|
|
41
|
-
return filteredMembers;
|
|
42
|
-
return [...filteredMembers].sort((a, b) => {
|
|
43
|
-
const col = sortDescriptor.column;
|
|
44
|
-
const first = col === "user" ? a.user.name || a.user.email : String(a[col]);
|
|
45
|
-
const second = col === "user" ? b.user.name || b.user.email : String(b[col]);
|
|
46
|
-
let cmp = first.localeCompare(second);
|
|
47
|
-
if (sortDescriptor.direction === "descending") {
|
|
48
|
-
cmp *= -1;
|
|
49
|
-
}
|
|
50
|
-
return cmp;
|
|
51
|
-
});
|
|
52
|
-
}, [sortDescriptor, filteredMembers]);
|
|
53
|
-
const [inviteOpen, setInviteOpen] = useState(false);
|
|
54
|
-
const isOwner = membersData?.members.some((member) => member.role === "owner" && member.userId === session?.user.id);
|
|
55
|
-
return (_jsxs("div", { className: cn("flex flex-col gap-3", className), ...props, children: [_jsxs("div", { className: "flex items-end justify-between gap-3", children: [_jsx("h3", { className: "truncate text-sm font-semibold", children: organizationLocalization.members }), _jsx(Button, { className: "shrink-0", size: "sm", isDisabled: isPending, onPress: () => setInviteOpen(true), children: organizationLocalization.inviteMember })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(SearchField, { className: "min-w-0", "aria-label": organizationLocalization.search, value: search, onChange: setSearch, isDisabled: isPending, children: _jsxs(SearchField.Group, { children: [_jsx(SearchField.SearchIcon, {}), _jsx(SearchField.Input, { placeholder: organizationLocalization.search, className: "sm:w-[200px]" }), _jsx(SearchField.ClearButton, {})] }) }), _jsxs(Dropdown, { children: [_jsxs(Button, { size: "sm", variant: "secondary", isDisabled: isPending, children: [_jsx(Funnel, {}), organizationLocalization.role] }), _jsx(Dropdown.Popover, { children: _jsxs(Dropdown.Menu, { selectionMode: "single", selectedKeys: new Set([roleFilter]), onSelectionChange: (keys) => {
|
|
56
|
-
const key = [...keys][0];
|
|
57
|
-
setRoleFilter(key ?? "all");
|
|
58
|
-
}, children: [_jsxs(Dropdown.Item, { id: "all", textValue: organizationLocalization.all, children: [_jsx(Label, { children: organizationLocalization.all }), _jsx(Dropdown.ItemIndicator, {})] }), Object.entries(roles).map(([role, label]) => (_jsxs(Dropdown.Item, { id: role, textValue: label, children: [_jsx(Label, { children: label }), _jsx(Dropdown.ItemIndicator, {})] }, role)))] }) })] })] }), roleFilter !== "all" && (_jsxs(Chip, { size: "sm", variant: "secondary", className: "w-fit", children: [_jsxs(Chip.Label, { children: [organizationLocalization.role, ":", " ", _jsx("span", { className: "capitalize", children: roles?.[roleFilter] ?? roleFilter })] }), _jsx("button", { type: "button", "aria-label": organizationLocalization.clear, className: "text-muted hover:text-foreground inline-flex cursor-pointer items-center", onClick: () => setRoleFilter("all"), children: _jsx(Xmark, { className: "size-3" }) })] })), _jsx(Table, { children: _jsx(Table.ScrollContainer, { children: _jsxs(Table.Content, { "aria-label": organizationLocalization.members, sortDescriptor: sortDescriptor, onSortChange: (descriptor) => {
|
|
59
|
-
const shouldReset = sortDescriptor?.column === descriptor.column &&
|
|
60
|
-
descriptor.direction === "ascending";
|
|
61
|
-
setSortDescriptor(shouldReset ? undefined : descriptor);
|
|
62
|
-
}, children: [_jsxs(Table.Header, { children: [_jsx(Table.Column, { allowsSorting: true, isRowHeader: true, id: "user", children: ({ sortDirection }) => (_jsx(SortableColumnHeader, { sortDirection: sortDirection, children: organizationLocalization.member })) }), _jsx(Table.Column, { allowsSorting: true, id: "role", children: ({ sortDirection }) => (_jsx(SortableColumnHeader, { sortDirection: sortDirection, children: organizationLocalization.role })) }), _jsx(Table.Column, { className: "text-end", children: organizationLocalization.actions })] }), _jsx(Table.Body, { children: isPending ? (_jsx(OrganizationMemberRowSkeleton, {})) : (!!activeOrganization &&
|
|
63
|
-
sortedMembers?.map((member) => (_jsx(OrganizationMemberRow, { member: member, isOwner: isOwner, organization: activeOrganization }, member.id)))) })] }) }) })] }), _jsx(InviteMemberDialog, { isOpen: inviteOpen, onOpenChange: setInviteOpen })] }));
|
|
64
|
-
}
|
|
65
|
-
function SortableColumnHeader({ children, sortDirection }) {
|
|
66
|
-
return (_jsxs("span", { className: "flex items-center justify-between", children: [children, !!sortDirection && (_jsx(ChevronUp, { className: cn("size-3 transform transition-transform duration-100 ease-out", sortDirection === "descending" ? "rotate-180" : "") }))] }));
|
|
67
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cn } from "@heroui/react";
|
|
3
|
-
import { OrganizationInvitations } from "./organization-invitations";
|
|
4
|
-
import { OrganizationMembers } from "./organization-members";
|
|
5
|
-
/**
|
|
6
|
-
* Organization people UI: members table (see {@link OrganizationMembers}), then org
|
|
7
|
-
* invitations.
|
|
8
|
-
*/
|
|
9
|
-
export function OrganizationPeople({ className, ...props }) {
|
|
10
|
-
return (_jsxs("div", { className: cn("flex flex-col gap-4 md:gap-6", className), ...props, children: [_jsx(OrganizationMembers, {}), _jsx(OrganizationInvitations, {})] }));
|
|
11
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useActiveOrganization, useAuth, useAuthPlugin, useUpdateOrganization } from "@better-auth-ui/react";
|
|
3
|
-
import { Button, Card, cn, FieldError, Form, Input, Label, Skeleton, Spinner, TextField, toast } from "@heroui/react";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
import { ChangeOrganizationLogo } from "./change-organization-logo";
|
|
7
|
-
import { SlugField } from "./slug-field";
|
|
8
|
-
/**
|
|
9
|
-
* Profile card for the active organization: logo (when enabled), display name, and slug.
|
|
10
|
-
*/
|
|
11
|
-
export function OrganizationProfile({ className, variant, ...props }) {
|
|
12
|
-
const { authClient, localization } = useAuth();
|
|
13
|
-
const { localization: organizationLocalization } = useAuthPlugin(organizationPlugin);
|
|
14
|
-
const { data: activeOrganization } = useActiveOrganization(authClient);
|
|
15
|
-
const [slug, setSlug] = useState(activeOrganization?.slug ?? "");
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
setSlug(activeOrganization?.slug ?? "");
|
|
18
|
-
}, [activeOrganization?.slug]);
|
|
19
|
-
const { mutate: commitOrganizationUpdate, isPending } = useUpdateOrganization(authClient, {
|
|
20
|
-
onSuccess: () => toast.success(organizationLocalization.organizationUpdatedSuccess)
|
|
21
|
-
});
|
|
22
|
-
function handleSubmit(e) {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
if (!activeOrganization)
|
|
25
|
-
return;
|
|
26
|
-
const formData = new FormData(e.currentTarget);
|
|
27
|
-
const name = formData.get("name");
|
|
28
|
-
commitOrganizationUpdate({
|
|
29
|
-
data: { name, slug }
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
const inputVariant = variant === "transparent" ? "primary" : "secondary";
|
|
33
|
-
return (_jsxs("div", { children: [_jsx("h2", { className: cn("mb-3 text-sm font-semibold"), children: organizationLocalization.organizationProfile }), _jsx(Card, { className: cn(className), variant: variant, ...props, children: _jsx(Card.Content, { children: _jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsx(ChangeOrganizationLogo, {}), _jsxs(TextField, { name: "name", defaultValue: activeOrganization?.name, isDisabled: isPending || !activeOrganization, children: [_jsx(Label, { children: organizationLocalization.name }), _jsx(Input, { className: cn(!activeOrganization && "hidden"), autoComplete: "organization", placeholder: organizationLocalization.namePlaceholder, variant: inputVariant }), !activeOrganization && (_jsx(Skeleton, { className: "h-10 w-full rounded-xl md:h-9" })), _jsx(FieldError, {})] }, `${activeOrganization?.id}-${activeOrganization?.name}-name`), activeOrganization ? (_jsx(SlugField, { value: slug, onChange: setSlug, currentSlug: activeOrganization.slug, isDisabled: isPending, variant: inputVariant })) : (_jsxs(TextField, { isDisabled: true, children: [_jsx(Label, { children: organizationLocalization.slug }), _jsx(Skeleton, { className: "h-10 w-full rounded-xl md:h-9" })] })), _jsxs(Button, { type: "submit", isPending: isPending, isDisabled: !activeOrganization, size: "sm", className: "mt-1", children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.settings.saveChanges] })] }) }) })] }));
|
|
34
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthPlugin, useSetActiveOrganization } from "@better-auth-ui/react";
|
|
3
|
-
import { Gear } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Spinner } from "@heroui/react";
|
|
5
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
6
|
-
import { OrganizationView } from "./organization-view";
|
|
7
|
-
/**
|
|
8
|
-
* Single organization row: logo and labels via {@link OrganizationView}, plus Manage.
|
|
9
|
-
*/
|
|
10
|
-
export function OrganizationRow({ organization }) {
|
|
11
|
-
const { authClient, basePaths, navigate } = useAuth();
|
|
12
|
-
const { localization: organizationLocalization, viewPaths: organizationViewPaths, slug } = useAuthPlugin(organizationPlugin);
|
|
13
|
-
const { mutate: setActiveOrganization, isPending: setActivePending } = useSetActiveOrganization(authClient, {
|
|
14
|
-
onSuccess: () => {
|
|
15
|
-
navigate({
|
|
16
|
-
to: `${basePaths.organization}/${organizationViewPaths.organization.settings}`
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
function manageOrganization() {
|
|
21
|
-
if (slug !== undefined) {
|
|
22
|
-
navigate({
|
|
23
|
-
to: `${basePaths.organization}/${organization.slug}/${organizationViewPaths.organization.settings}`
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
setActiveOrganization({ organizationId: organization.id });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(OrganizationView, { organization: organization }), _jsxs(Button, { className: "ml-auto shrink-0", variant: "outline", size: "sm", isPending: setActivePending, onPress: manageOrganization, "aria-label": organizationLocalization.manage, children: [setActivePending ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Gear, {}), organizationLocalization.manage] })] }));
|
|
31
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth } from "@better-auth-ui/react";
|
|
3
|
-
import { cn } from "@heroui/react";
|
|
4
|
-
import { OrganizationDangerZone } from "./organization-danger-zone";
|
|
5
|
-
import { OrganizationProfile } from "./organization-profile";
|
|
6
|
-
/**
|
|
7
|
-
* Organization settings UI: profile card, plugin-contributed cards
|
|
8
|
-
* (`organizationCards`), then danger zone.
|
|
9
|
-
*/
|
|
10
|
-
export function OrganizationSettings({ className, variant, ...props }) {
|
|
11
|
-
const { plugins } = useAuth();
|
|
12
|
-
return (_jsxs("div", { className: cn("flex flex-col gap-4 md:gap-6", className), ...props, children: [_jsx(OrganizationProfile, { variant: variant }), plugins.flatMap((plugin) => plugin.organizationCards?.map((Card, index) => (_jsx(Card, { variant: variant }, `${plugin.id}-${index.toString()}`)))), _jsx(OrganizationDangerZone, { variant: variant })] }));
|
|
13
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useActiveOrganization, useAuth, useAuthPlugin, useListOrganizations, useSession, useSetActiveOrganization } from "@better-auth-ui/react";
|
|
3
|
-
import { ChevronsExpandVertical, CirclePlus, Gear } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, cn, Dropdown, Label, Link } from "@heroui/react";
|
|
5
|
-
import { buttonVariants } from "@heroui/styles";
|
|
6
|
-
import { useState } from "react";
|
|
7
|
-
import { organizationPlugin } from "../../../lib/auth/organization-plugin";
|
|
8
|
-
import { UserView } from "../user/user-view";
|
|
9
|
-
import { CreateOrganizationDialog } from "./create-organization-dialog";
|
|
10
|
-
import { OrganizationView } from "./organization-view";
|
|
11
|
-
/**
|
|
12
|
-
* Renders an organizations dropdown with a trigger button,
|
|
13
|
-
* header summary, and a menu of organizations to switch to.
|
|
14
|
-
*/
|
|
15
|
-
export function OrganizationSwitcher({ className, hideCreate, hidePersonal, hideSettings, hideSlug = true, setActive, placement, variant = "ghost", size = "md", trigger, ...props }) {
|
|
16
|
-
const { authClient, navigate, basePaths, localization, viewPaths } = useAuth();
|
|
17
|
-
const { data: session, isPending: sessionPending } = useSession(authClient);
|
|
18
|
-
const { localization: organizationLocalization, viewPaths: organizationViewPaths, slug } = useAuthPlugin(organizationPlugin);
|
|
19
|
-
const { data: activeOrganization, isPending: activeOrganizationPending } = useActiveOrganization(authClient);
|
|
20
|
-
const { data: organizations, isPending: organizationsPending } = useListOrganizations(authClient);
|
|
21
|
-
const { mutate: setActiveOrganization } = useSetActiveOrganization(authClient);
|
|
22
|
-
const isPending = sessionPending ||
|
|
23
|
-
(!!session && (organizationsPending || activeOrganizationPending));
|
|
24
|
-
const [createOpen, setCreateOpen] = useState(false);
|
|
25
|
-
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
26
|
-
function handleSetActive(organization) {
|
|
27
|
-
if (setActive) {
|
|
28
|
-
setActive(organization);
|
|
29
|
-
}
|
|
30
|
-
else if (slug !== undefined) {
|
|
31
|
-
navigate({
|
|
32
|
-
to: organization
|
|
33
|
-
? `${basePaths.organization}/${organization.slug}/${organizationViewPaths.organization.settings}`
|
|
34
|
-
: `${basePaths.settings}/${viewPaths.settings.account}`
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
setActiveOrganization({ organizationId: organization?.id ?? null });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Dropdown, { isOpen: dropdownOpen, onOpenChange: setDropdownOpen, children: [trigger ? (_jsx(Dropdown.Trigger, { children: trigger })) : (_jsxs(Button, { variant: variant, className: cn("h-auto px-2 py-2 text-left", className), isDisabled: !session || isPending, "aria-label": organizationLocalization.organization, ...props, children: [isPending ? (_jsx(OrganizationView, { size: size, isPending: true, hideRole: true, hideSlug: hideSlug })) : activeOrganization ? (_jsx(OrganizationView, { size: size, hideRole: true, hideSlug: hideSlug })) : session && !hidePersonal ? (_jsx(UserView, { size: size, hideSubtitle: hideSlug })) : (_jsx(OrganizationView, { size: size, hideRole: true, hideSlug: hideSlug, organization: {
|
|
42
|
-
name: organizationLocalization.organization
|
|
43
|
-
} })), _jsx(ChevronsExpandVertical, { className: "size-3 shrink-0 text-muted" })] })), _jsxs(Dropdown.Popover, { placement: placement, className: "max-w-svw", children: [activeOrganization ? (_jsxs("div", { className: "flex items-center justify-between gap-4 px-4 pt-3", children: [_jsx(OrganizationView, { hideRole: true, hideSlug: hideSlug, organization: activeOrganization }), !hideSettings && (_jsxs(Link, { href: slug
|
|
44
|
-
? `${basePaths.organization}/${slug}/${organizationViewPaths.organization.settings}`
|
|
45
|
-
: `${basePaths.organization}/${organizationViewPaths.organization.settings}`, className: cn(buttonVariants({ variant: "outline", size: "sm" }), "shrink-0 gap-2"), onPress: () => setDropdownOpen(false), children: [_jsx(Gear, { className: "text-muted" }), organizationLocalization.manage] }))] })) : !isPending && session?.user && !hidePersonal ? (_jsxs("div", { className: "flex items-center justify-between gap-4 px-4 pt-3", children: [_jsx(UserView, { hideSubtitle: hideSlug }), !hideSettings && (_jsxs(Link, { href: `${basePaths.settings}/${viewPaths.settings.account}`, className: cn(buttonVariants({ variant: "outline", size: "sm" }), "shrink-0 gap-2"), onPress: () => setDropdownOpen(false), children: [_jsx(Gear, { className: "text-muted" }), localization.settings.settings] }))] })) : null, _jsxs(Dropdown.Menu, { children: [!!activeOrganization && !hidePersonal && (_jsx(Dropdown.Item, { textValue: organizationLocalization.personalAccount, onPress: () => handleSetActive(null), children: _jsx(UserView, { hideSubtitle: hideSlug }) })), organizations
|
|
46
|
-
?.filter((organization) => organization.id !== activeOrganization?.id)
|
|
47
|
-
?.map((organization) => (_jsx(Dropdown.Item, { textValue: organization.name, onPress: () => handleSetActive(organization), children: _jsx(OrganizationView, { hideRole: true, hideSlug: hideSlug, organization: organization }) }, organization.id))), !hideCreate && (_jsxs(Dropdown.Item, { textValue: organizationLocalization.createOrganization, onPress: () => setCreateOpen(true), children: [_jsx(CirclePlus, { className: "text-muted" }), _jsx(Label, { children: organizationLocalization.createOrganization })] }))] })] })] }), _jsx(CreateOrganizationDialog, { isOpen: createOpen, onOpenChange: setCreateOpen })] }));
|
|
48
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { cn, Skeleton } from "@heroui/react";
|
|
3
|
-
import { OrganizationLogo } from "./organization-logo";
|
|
4
|
-
/**
|
|
5
|
-
* Placeholder matching {@link OrganizationView} while organization data loads.
|
|
6
|
-
*/
|
|
7
|
-
export function OrganizationViewSkeleton({ className, hideSlug, size = "md", ...props }) {
|
|
8
|
-
return (_jsxs("div", { className: cn("flex min-w-0 items-center gap-2", className), ...props, children: [_jsx(OrganizationLogo, { isPending: true, className: size === "sm" ? "size-5" : undefined, size: size === "lg" ? "md" : "sm" }), _jsxs("div", { className: "flex flex-col min-w-0 gap-1", children: [_jsx(Skeleton, { className: "h-3.5 w-20 rounded-lg" }), !hideSlug && (_jsx(Skeleton, { className: "h-3 w-28 rounded-lg mt-[0.5px] mb-0.5" }))] })] }));
|
|
9
|
-
}
|