[CORL-97] Add user status details popover to user drawer (#2431)

* show tooltip for user status details

* localize strings

* fix merge conflict

* fix date formatting in user details popover

* update snapshot

* fix rebase
This commit is contained in:
Tessa Thornton
2019-08-07 16:22:47 -04:00
committed by Kim Gardner
parent 3f307002e2
commit ff964b54a3
4 changed files with 185 additions and 3 deletions
@@ -2,12 +2,12 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { ReadyState } from "react-relay";
import { UserStatusChangeContainer } from "coral-admin/components/UserStatus";
import { CopyButton } from "coral-framework/components";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import { graphql, QueryRenderer } from "coral-framework/lib/relay";
import { UserHistoryDrawerQuery as QueryTypes } from "coral-admin/__generated__/UserHistoryDrawerQuery.graphql";
import { UserStatusChangeContainer } from "coral-admin/components/UserStatus";
import {
Button,
CallOut,
@@ -18,6 +18,7 @@ import {
} from "coral-ui/components";
import Tabs from "./Tabs";
import UserStatusDetailsContainer from "./UserStatusDetailsContainer";
import styles from "./UserHistoryDrawerQuery.css";
@@ -48,6 +49,7 @@ const UserHistoryDrawerQuery: FunctionComponent<Props> = ({
username
email
createdAt
...UserStatusDetailsContainer_user
...UserStatusChangeContainer_user
}
settings {
@@ -92,7 +94,7 @@ const UserHistoryDrawerQuery: FunctionComponent<Props> = ({
<span>{user.username}</span>
</Flex>
<div className={styles.userStatus}>
<Flex alignItems="center">
<Flex alignItems="center" itemGutter="half">
<div className={styles.userStatusLabel}>
<Typography variant="bodyCopyBold" container="div">
<Flex alignItems="center" itemGutter="half">
@@ -103,8 +105,13 @@ const UserHistoryDrawerQuery: FunctionComponent<Props> = ({
</Typography>
</div>
<div className={styles.userStatusChange}>
<UserStatusChangeContainer settings={settings} user={user} />
<UserStatusChangeContainer
settings={settings}
user={user}
fullWidth={false}
/>
</div>
<UserStatusDetailsContainer user={user} />
</Flex>
</div>
<div className={styles.userDetails}>
@@ -0,0 +1,169 @@
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, useMemo } from "react";
import { UserStatusDetailsContainer_user as UserData } from "coral-admin/__generated__/UserStatusDetailsContainer_user.graphql";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import {
BaseButton,
Box,
ClickOutside,
Icon,
Popover,
Typography,
} from "coral-ui/components";
interface Props {
user: UserData;
}
const UserStatusDetailsContainer: FunctionComponent<Props> = ({ user }) => {
if (!user.status.ban.active && !user.status.suspension.active) {
return null;
}
const activeBan = useMemo(() => {
return user.status.ban.history.find(item => item.active);
}, [user]);
const activeSuspension = useMemo(() => {
return user.status.suspension.history.find(item => item.active);
}, [user]);
const { locales } = useCoralContext();
const formatter = new Intl.DateTimeFormat(locales, {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
return (
<div>
<Popover
placement="bottom"
id="userStatus-details-popover"
body={({ toggleVisibility }) => (
<ClickOutside onClickOutside={toggleVisibility}>
<Box p={2}>
{activeBan && (
<div>
<Localized
id="userDetails-banned-on"
$timestamp={formatter.format(activeBan.createdAt)}
strong={<strong />}
>
<Typography>
<strong>Banned on </strong>{" "}
{formatter.format(activeBan.createdAt)}
</Typography>
</Localized>
{activeBan.createdBy && (
<Localized
id="userDetails-banned-by"
strong={<strong />}
$username={activeBan.createdBy.username}
>
<Typography>
<strong>by </strong>
{activeBan.createdBy.username}
</Typography>
</Localized>
)}
</div>
)}
{activeSuspension && (
<div>
{activeSuspension.createdBy && (
<Localized
id="userDetails-suspended-by"
strong={<strong />}
$username={activeSuspension.createdBy.username}
>
<Typography>
<strong>Suspended by </strong>
{activeSuspension.createdBy.username}
</Typography>
</Localized>
)}
<Localized
id="userDetails-suspension-start"
strong={<strong />}
$timestamp={formatter.format(activeSuspension.from.start)}
>
<Typography>
<strong>Start: </strong>
{formatter.format(activeSuspension.from.start)}
</Typography>
</Localized>
<Localized
strong={<strong />}
$timestamp={formatter.format(activeSuspension.from.finish)}
id="userDetails-suspension-start"
>
<Typography>
<strong>End: </strong>
{formatter.format(activeSuspension.from.finish)}
</Typography>
</Localized>
</div>
)}
</Box>
</ClickOutside>
)}
>
{({ toggleVisibility, ref }) => (
<BaseButton
onClick={evt => {
evt.stopPropagation();
toggleVisibility();
}}
aria-label="View user status details"
ref={ref}
>
<Icon size="md" color="inherit">
info
</Icon>
</BaseButton>
)}
</Popover>
</div>
);
};
const enhanced = withFragmentContainer<Props>({
user: graphql`
fragment UserStatusDetailsContainer_user on User {
status {
ban {
active
history {
active
createdAt
createdBy {
username
}
}
}
suspension {
until
active
history {
active
from {
start
finish
}
createdBy {
username
}
}
}
}
}
`,
})(UserStatusDetailsContainer);
export default enhanced;
+6
View File
@@ -682,3 +682,9 @@ invite-goToAdmin = Go to { -product-name } Admin
invite-goToOrganization = Go to { $organizationName }
invite-tokenNotFound =
The specified link is invalid, check to see if it was copied correctly.
userDetails-banned-on = <strong>Banned on</strong> { $timestamp }
userDetails-banned-by = <strong>by</strong> { $username }
userDetails-suspended-by = <strong>Suspended by</strong> { $username }
userDetails-suspension-start = <strong>Start:</strong> { $timestamp }
userDetails-suspension-end = <strong>End:</strong> { $timestamp }