feat: Improve translations, fade inactive collection members
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { subMinutes } from "date-fns";
|
||||
import { computed, observable } from "mobx";
|
||||
import { now } from "mobx-utils";
|
||||
import type { Role } from "@shared/types";
|
||||
import ParanoidModel from "./ParanoidModel";
|
||||
import Field from "./decorators/Field";
|
||||
@@ -39,6 +41,17 @@ class User extends ParanoidModel {
|
||||
return !this.lastActiveAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user has been recently active. Recently is currently defined
|
||||
* as within the last 5 minutes.
|
||||
*
|
||||
* @returns true if the user has been active recently
|
||||
*/
|
||||
@computed
|
||||
get isRecentlyActive(): boolean {
|
||||
return new Date(this.lastActiveAt) > subMinutes(now(10000), 5);
|
||||
}
|
||||
|
||||
@computed
|
||||
get role(): Role {
|
||||
if (this.isAdmin) {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { sortBy } from "lodash";
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { PAGINATION_SYMBOL } from "~/stores/BaseStore";
|
||||
import Collection from "~/models/Collection";
|
||||
import User from "~/models/User";
|
||||
import Avatar from "~/components/Avatar";
|
||||
import Facepile from "~/components/Facepile";
|
||||
import Fade from "~/components/Fade";
|
||||
import NudeButton from "~/components/NudeButton";
|
||||
@@ -17,7 +21,8 @@ type Props = {
|
||||
|
||||
const MembershipPreview = ({ collection, limit = 8 }: Props) => {
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [totalMemberships, setTotalMemberships] = React.useState(0);
|
||||
const [usersCount, setUsersCount] = React.useState(0);
|
||||
const [groupsCount, setGroupsCount] = React.useState(0);
|
||||
const { t } = useTranslation();
|
||||
const { memberships, collectionGroupMemberships, users } = useStores();
|
||||
const collectionUsers = users.inCollection(collection.id);
|
||||
@@ -39,9 +44,8 @@ const MembershipPreview = ({ collection, limit = 8 }: Props) => {
|
||||
memberships.fetchPage(options),
|
||||
collectionGroupMemberships.fetchPage(options),
|
||||
]);
|
||||
setTotalMemberships(
|
||||
users[PAGINATION_SYMBOL].total + groups[PAGINATION_SYMBOL].total
|
||||
);
|
||||
setUsersCount(users[PAGINATION_SYMBOL].total);
|
||||
setGroupsCount(groups[PAGINATION_SYMBOL].total);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -60,24 +64,55 @@ const MembershipPreview = ({ collection, limit = 8 }: Props) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const overflow = totalMemberships - collectionUsers.length;
|
||||
const overflow = usersCount - groupsCount - collectionUsers.length;
|
||||
|
||||
return (
|
||||
<NudeButton
|
||||
context={context}
|
||||
action={editCollectionPermissions}
|
||||
tooltip={{
|
||||
tooltip: t("Users and groups with access"),
|
||||
tooltip:
|
||||
usersCount > 0
|
||||
? groupsCount > 0
|
||||
? groupsCount > 1
|
||||
? t(
|
||||
`{{ usersCount }} users and {{ groupsCount }} groups with access`,
|
||||
{ usersCount, count: usersCount }
|
||||
)
|
||||
: t(`{{ usersCount }} users and a group have access`, {
|
||||
usersCount,
|
||||
count: usersCount,
|
||||
})
|
||||
: t(`{{ usersCount }} users with access`, {
|
||||
usersCount,
|
||||
count: usersCount,
|
||||
})
|
||||
: t(`{{ groupsCount }} groups with access`, {
|
||||
groupsCount,
|
||||
count: groupsCount,
|
||||
}),
|
||||
delay: 250,
|
||||
}}
|
||||
width="auto"
|
||||
height="auto"
|
||||
>
|
||||
<Fade>
|
||||
<Facepile users={collectionUsers} overflow={overflow} limit={limit} />
|
||||
<Facepile
|
||||
users={sortBy(collectionUsers, "lastActiveAt")}
|
||||
overflow={overflow}
|
||||
limit={limit}
|
||||
renderAvatar={(user) => (
|
||||
<StyledAvatar user={user} src={user.avatarUrl} size={32} />
|
||||
)}
|
||||
/>
|
||||
</Fade>
|
||||
</NudeButton>
|
||||
);
|
||||
};
|
||||
|
||||
const StyledAvatar = styled(Avatar)<{ user: User }>`
|
||||
transition: opacity 250ms ease-in-out;
|
||||
opacity: ${(props) => (props.user.isRecentlyActive ? 1 : 0.5)};
|
||||
`;
|
||||
|
||||
export default observer(MembershipPreview);
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
"mime-types": "^2.1.35",
|
||||
"mobx": "^4.15.4",
|
||||
"mobx-react": "^6.3.1",
|
||||
"mobx-utils": "^6.0.5",
|
||||
"natural-sort": "^1.0.0",
|
||||
"node-fetch": "2.6.7",
|
||||
"node-htmldiff": "^0.9.4",
|
||||
@@ -351,4 +352,4 @@
|
||||
"jpeg-js": "0.4.4"
|
||||
},
|
||||
"version": "0.66.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +347,14 @@
|
||||
"Get started by creating a new one!": "Get started by creating a new one!",
|
||||
"Create a document": "Create a document",
|
||||
"Manage permissions": "Manage permissions",
|
||||
"Users and groups with access": "Users and groups with access",
|
||||
"{{ usersCount }} users and {{ groupsCount }} groups with access": "{{ usersCount }} user and {{ groupsCount }} groups with access",
|
||||
"{{ usersCount }} users and {{ groupsCount }} groups with access_plural": "{{ usersCount }} users and {{ groupsCount }} groups with access",
|
||||
"{{ usersCount }} users and a group have access": "{{ usersCount }} user and a group have access",
|
||||
"{{ usersCount }} users and a group have access_plural": "{{ usersCount }} users and a group have access",
|
||||
"{{ usersCount }} users with access": "{{ usersCount }} user with access",
|
||||
"{{ usersCount }} users with access_plural": "{{ usersCount }} users with access",
|
||||
"{{ groupsCount }} groups with access": "{{ groupsCount }} group with access",
|
||||
"{{ groupsCount }} groups with access_plural": "{{ groupsCount }} groups with access",
|
||||
"The collection was updated": "The collection was updated",
|
||||
"You can edit the name and other details at any time, however doing so often might confuse your team mates.": "You can edit the name and other details at any time, however doing so often might confuse your team mates.",
|
||||
"Name": "Name",
|
||||
|
||||
11
yarn.lock
11
yarn.lock
@@ -1043,7 +1043,7 @@
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.16.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6"
|
||||
integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==
|
||||
@@ -8835,7 +8835,7 @@ is-ci@^2.0.0:
|
||||
dependencies:
|
||||
ci-info "^2.0.0"
|
||||
|
||||
is-core-module@^2.2.0, is-core-module@^2.8.0, is-core-module@^2.9.0:
|
||||
is-core-module@^2.8.0, is-core-module@^2.9.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
|
||||
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
|
||||
@@ -10968,6 +10968,11 @@ mobx-react@^6.3.1:
|
||||
dependencies:
|
||||
mobx-react-lite "^2.2.0"
|
||||
|
||||
mobx-utils@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/mobx-utils/-/mobx-utils-6.0.5.tgz#0cce9afb07fbba1fb559f959f8cea1f44baa7252"
|
||||
integrity sha512-QOduwicYedD4mwYZRl8+c3BalljFDcubg+PUGqBkn8tOuBoj2q7GhjXBP6JXM9J+Zh+2mePK8IoToeLfqr3Z/w==
|
||||
|
||||
mobx@^4.15.4:
|
||||
version "4.15.7"
|
||||
resolved "https://registry.yarnpkg.com/mobx/-/mobx-4.15.7.tgz#933281268c3b4658b6cf2526e872cf78ea48ab95"
|
||||
@@ -11814,7 +11819,7 @@ path-key@^3.0.0, path-key@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-parse@^1.0.6, path-parse@^1.0.7:
|
||||
path-parse@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
Reference in New Issue
Block a user