0
Fork 0
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:
Charles Zhao 2024-04-09 17:30:47 +08:00 committed by GitHub
parent 2c97cd6898
commit 06083296c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 36 additions and 15 deletions

View file

@ -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`, {

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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 },

View file

@ -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);
}
}