mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor(console): improve tenant member role related experience (#5659)
This commit is contained in:
parent
2c97cd6898
commit
06083296c1
5 changed files with 36 additions and 15 deletions
|
@ -1,7 +1,7 @@
|
||||||
import { TenantRole } from '@logto/schemas';
|
import { TenantRole } from '@logto/schemas';
|
||||||
import { getUserDisplayName } from '@logto/shared/universal';
|
import { getUserDisplayName } from '@logto/shared/universal';
|
||||||
import { useContext, useMemo, useState } from 'react';
|
import { useContext, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
import ReactModal from 'react-modal';
|
import ReactModal from 'react-modal';
|
||||||
|
|
||||||
import { useAuthedCloudApi } from '@/cloud/hooks/use-cloud-api';
|
import { useAuthedCloudApi } from '@/cloud/hooks/use-cloud-api';
|
||||||
|
@ -11,6 +11,7 @@ import Button from '@/ds-components/Button';
|
||||||
import FormField from '@/ds-components/FormField';
|
import FormField from '@/ds-components/FormField';
|
||||||
import ModalLayout from '@/ds-components/ModalLayout';
|
import ModalLayout from '@/ds-components/ModalLayout';
|
||||||
import Select, { type Option } from '@/ds-components/Select';
|
import Select, { type Option } from '@/ds-components/Select';
|
||||||
|
import { useConfirmModal } from '@/hooks/use-confirm-modal';
|
||||||
import * as modalStyles from '@/scss/modal.module.scss';
|
import * as modalStyles from '@/scss/modal.module.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -25,6 +26,7 @@ function EditMemberModal({ user, isOpen, onClose }: Props) {
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [role, setRole] = useState(TenantRole.Collaborator);
|
const [role, setRole] = useState(TenantRole.Collaborator);
|
||||||
|
const { show } = useConfirmModal();
|
||||||
const cloudApi = useAuthedCloudApi();
|
const cloudApi = useAuthedCloudApi();
|
||||||
|
|
||||||
const roleOptions: Array<Option<TenantRole>> = useMemo(
|
const roleOptions: Array<Option<TenantRole>> = useMemo(
|
||||||
|
@ -36,6 +38,19 @@ function EditMemberModal({ user, isOpen, onClose }: Props) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
|
if (role === TenantRole.Admin) {
|
||||||
|
const [result] = await show({
|
||||||
|
ModalContent: () => (
|
||||||
|
<Trans components={{ ul: <ul />, li: <li /> }}>{t('assign_admin_confirm')}</Trans>
|
||||||
|
),
|
||||||
|
confirmButtonText: 'general.confirm',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
await cloudApi.put(`/api/tenants/:tenantId/members/:userId/roles`, {
|
await cloudApi.put(`/api/tenants/:tenantId/members/:userId/roles`, {
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
@use '@/scss/underscore' as _;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-inline-start: _.unit(6);
|
|
||||||
|
|
||||||
> li {
|
|
||||||
font: var(--font-body-2);
|
|
||||||
margin-block: _.unit(2);
|
|
||||||
padding-inline-start: _.unit(1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,7 +18,6 @@ import useEmailInputUtils from '../InviteEmailsInput/hooks';
|
||||||
import { type InviteMemberForm } from '../types';
|
import { type InviteMemberForm } from '../types';
|
||||||
|
|
||||||
import Footer from './Footer';
|
import Footer from './Footer';
|
||||||
import './index.module.scss';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { TenantRole } from '@logto/schemas';
|
||||||
import { condArray, conditional } from '@silverhand/essentials';
|
import { condArray, conditional } from '@silverhand/essentials';
|
||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -14,6 +15,7 @@ import Table from '@/ds-components/Table';
|
||||||
import Tag from '@/ds-components/Tag';
|
import Tag from '@/ds-components/Tag';
|
||||||
import { type RequestError } from '@/hooks/use-api';
|
import { type RequestError } from '@/hooks/use-api';
|
||||||
import useCurrentTenantScopes from '@/hooks/use-current-tenant-scopes';
|
import useCurrentTenantScopes from '@/hooks/use-current-tenant-scopes';
|
||||||
|
import useCurrentUser from '@/hooks/use-current-user';
|
||||||
|
|
||||||
import EditMemberModal from '../EditMemberModal';
|
import EditMemberModal from '../EditMemberModal';
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ function Members() {
|
||||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.tenant_members' });
|
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.tenant_members' });
|
||||||
const cloudApi = useAuthedCloudApi();
|
const cloudApi = useAuthedCloudApi();
|
||||||
const { currentTenantId } = useContext(TenantsContext);
|
const { currentTenantId } = useContext(TenantsContext);
|
||||||
|
const { user: currentUser } = useCurrentUser();
|
||||||
const { canRemoveMember, canUpdateMemberRole } = useCurrentTenantScopes();
|
const { canRemoveMember, canUpdateMemberRole } = useCurrentTenantScopes();
|
||||||
|
|
||||||
const { data, error, isLoading, mutate } = useSWR<TenantMemberResponse[], RequestError>(
|
const { data, error, isLoading, mutate } = useSWR<TenantMemberResponse[], RequestError>(
|
||||||
|
@ -55,9 +58,12 @@ function Members() {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
return organizationRoles.map(({ id, name }) => (
|
return organizationRoles.map(({ id }) => (
|
||||||
<Tag key={id} variant="cell">
|
<Tag key={id} variant="cell">
|
||||||
<RoleOption value={id} title={name} />
|
<RoleOption
|
||||||
|
value={id}
|
||||||
|
title={t(id === TenantRole.Admin ? 'admin' : 'collaborator')}
|
||||||
|
/>
|
||||||
</Tag>
|
</Tag>
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -85,6 +91,8 @@ function Members() {
|
||||||
)}
|
)}
|
||||||
onDelete={conditional(
|
onDelete={conditional(
|
||||||
canRemoveMember &&
|
canRemoveMember &&
|
||||||
|
// Cannot remove self from members list
|
||||||
|
currentUser?.id !== user.id &&
|
||||||
(async () => {
|
(async () => {
|
||||||
await cloudApi.delete(`/api/tenants/:tenantId/members/:userId`, {
|
await cloudApi.delete(`/api/tenants/:tenantId/members/:userId`, {
|
||||||
params: { tenantId: currentTenantId, userId: user.id },
|
params: { tenantId: currentTenantId, userId: user.id },
|
||||||
|
|
|
@ -52,3 +52,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-inline-start: _.unit(6);
|
||||||
|
|
||||||
|
> li {
|
||||||
|
font: var(--font-body-2);
|
||||||
|
margin-block: _.unit(2);
|
||||||
|
padding-inline-start: _.unit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue