From 7d92b60e97a9b1a2dc5fc162a8994fdc349f0f51 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Tue, 13 Sep 2022 08:47:41 +0100 Subject: [PATCH] feat: Improve translations, fade inactive collection members --- app/models/User.ts | 13 ++++++ app/scenes/Collection/MembershipPreview.tsx | 49 ++++++++++++++++++--- package.json | 3 +- shared/i18n/locales/en_US/translation.json | 9 +++- yarn.lock | 11 +++-- 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/app/models/User.ts b/app/models/User.ts index c1753d722..b36602a02 100644 --- a/app/models/User.ts +++ b/app/models/User.ts @@ -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) { diff --git a/app/scenes/Collection/MembershipPreview.tsx b/app/scenes/Collection/MembershipPreview.tsx index 7998586d2..62e8cce3b 100644 --- a/app/scenes/Collection/MembershipPreview.tsx +++ b/app/scenes/Collection/MembershipPreview.tsx @@ -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 ( 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" > - + ( + + )} + /> ); }; +const StyledAvatar = styled(Avatar)<{ user: User }>` + transition: opacity 250ms ease-in-out; + opacity: ${(props) => (props.user.isRecentlyActive ? 1 : 0.5)}; +`; + export default observer(MembershipPreview); diff --git a/package.json b/package.json index ae8d7db35..329b95e55 100644 --- a/package.json +++ b/package.json @@ -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" -} \ No newline at end of file +} diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json index a1f2061ee..b397f789c 100644 --- a/shared/i18n/locales/en_US/translation.json +++ b/shared/i18n/locales/en_US/translation.json @@ -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", diff --git a/yarn.lock b/yarn.lock index f662d8be2..2bc868a22 100644 --- a/yarn.lock +++ b/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==