2021-06-09 14:32:17 +00:00
|
|
|
import React from "react";
|
|
|
|
|
import ProfileImage, { Profile } from "pages/common/ProfileImage";
|
|
|
|
|
|
|
|
|
|
import UserApi from "api/UserApi";
|
|
|
|
|
|
|
|
|
|
import { AppsmithNotification, NotificationTypes } from "entities/Notification";
|
|
|
|
|
import { getTypographyByKey } from "constants/DefaultTheme";
|
|
|
|
|
import { getCommentThreadURL } from "comments/utils";
|
2021-09-07 12:45:17 +00:00
|
|
|
import {
|
|
|
|
|
markNotificationAsReadRequest,
|
|
|
|
|
setIsNotificationsListVisible,
|
|
|
|
|
} from "actions/notificationActions";
|
2021-06-09 14:32:17 +00:00
|
|
|
|
|
|
|
|
import history from "utils/history";
|
|
|
|
|
import { useDispatch } from "react-redux";
|
2021-06-23 15:42:07 +00:00
|
|
|
|
|
|
|
|
import moment from "moment";
|
|
|
|
|
import styled from "styled-components";
|
2021-06-09 14:32:17 +00:00
|
|
|
|
2021-08-06 09:17:56 +00:00
|
|
|
import { APP_MODE } from "entities/App";
|
2021-07-02 06:04:36 +00:00
|
|
|
import OrgApi from "api/OrgApi";
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
isPermitted,
|
|
|
|
|
PERMISSION_TYPE,
|
|
|
|
|
} from "pages/Applications/permissionHelpers";
|
|
|
|
|
|
|
|
|
|
export const NOTIFICATION_HEIGHT = 82;
|
|
|
|
|
|
2021-06-09 14:32:17 +00:00
|
|
|
const Container = styled.div`
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%;
|
|
|
|
|
padding: ${(props) => props.theme.spaces[6]}px;
|
2021-07-02 06:04:36 +00:00
|
|
|
height: ${NOTIFICATION_HEIGHT}px;
|
2021-06-09 14:32:17 +00:00
|
|
|
|
|
|
|
|
${Profile} {
|
|
|
|
|
margin-right: ${(props) => props.theme.spaces[4]}px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const NotificationBodyContainer = styled.div`
|
|
|
|
|
${(props) => getTypographyByKey(props, "p1")};
|
|
|
|
|
& b {
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
2021-07-02 06:04:36 +00:00
|
|
|
|
|
|
|
|
& div {
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
display: -webkit-box;
|
|
|
|
|
-webkit-line-clamp: 2; /* number of lines to show */
|
|
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
}
|
2021-06-09 14:32:17 +00:00
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const FlexContainer = styled.div`
|
|
|
|
|
display: flex;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const Time = styled.div`
|
|
|
|
|
color: ${(props) => props.theme.colors.notifications.time};
|
|
|
|
|
${(props) => getTypographyByKey(props, "p3")};
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const ProfileImageContainer = styled.div`
|
|
|
|
|
position: relative;
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const UnreadIndicator = styled.div`
|
|
|
|
|
position: absolute;
|
|
|
|
|
right: 9px;
|
|
|
|
|
top: 0;
|
|
|
|
|
width: 9px;
|
|
|
|
|
height: 9px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background-color: ${(props) =>
|
|
|
|
|
props.theme.colors.notifications.unreadIndicator};
|
|
|
|
|
`;
|
|
|
|
|
|
2021-07-02 06:04:36 +00:00
|
|
|
const getModeFromUserRole = async (orgId: string) => {
|
|
|
|
|
try {
|
2021-07-16 08:31:26 +00:00
|
|
|
const response = (await OrgApi.fetchOrg({ orgId })) as any;
|
|
|
|
|
const userOrgPermissions = response?.data?.userPermissions || [];
|
2021-07-02 06:04:36 +00:00
|
|
|
const canPublish = isPermitted(
|
|
|
|
|
userOrgPermissions,
|
|
|
|
|
PERMISSION_TYPE.PUBLISH_APPLICATION,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return canPublish ? APP_MODE.EDIT : APP_MODE.PUBLISHED;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return APP_MODE.PUBLISHED;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getModeFromRoleAndDomain = (
|
|
|
|
|
modeFromRole: APP_MODE,
|
|
|
|
|
modeFromDomain: APP_MODE,
|
|
|
|
|
) => {
|
|
|
|
|
if (modeFromRole === APP_MODE.PUBLISHED) return APP_MODE.PUBLISHED;
|
|
|
|
|
return modeFromDomain;
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-23 15:42:07 +00:00
|
|
|
function CommentNotification(props: { notification: AppsmithNotification }) {
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const {
|
|
|
|
|
_id,
|
|
|
|
|
comment,
|
|
|
|
|
createdAt,
|
|
|
|
|
creationTime,
|
2021-08-13 04:58:42 +00:00
|
|
|
event,
|
2021-06-23 15:42:07 +00:00
|
|
|
id,
|
|
|
|
|
isRead,
|
|
|
|
|
} = props.notification;
|
|
|
|
|
const {
|
|
|
|
|
applicationId,
|
|
|
|
|
applicationName,
|
|
|
|
|
authorName,
|
|
|
|
|
authorUsername,
|
2021-07-02 06:04:36 +00:00
|
|
|
mode: modeFromComment,
|
|
|
|
|
orgId,
|
2021-06-23 15:42:07 +00:00
|
|
|
pageId,
|
|
|
|
|
// resolvedState, TODO get from comment thread
|
|
|
|
|
threadId,
|
|
|
|
|
} = comment;
|
|
|
|
|
|
|
|
|
|
const _createdAt = createdAt || creationTime;
|
|
|
|
|
const displayName = authorName || authorUsername;
|
2021-08-13 04:58:42 +00:00
|
|
|
let eventName = event;
|
|
|
|
|
if (!event || event == "CREATED") {
|
|
|
|
|
eventName = "left";
|
|
|
|
|
} else if (event == "TAGGED") {
|
|
|
|
|
eventName = "mentioned you in";
|
|
|
|
|
}
|
2021-06-23 15:42:07 +00:00
|
|
|
|
2021-07-02 06:04:36 +00:00
|
|
|
const handleClick = async () => {
|
|
|
|
|
const modeFromRole = await getModeFromUserRole(orgId);
|
|
|
|
|
const mode = getModeFromRoleAndDomain(modeFromRole, modeFromComment);
|
|
|
|
|
|
|
|
|
|
const commentThreadUrl = getCommentThreadURL({
|
|
|
|
|
applicationId,
|
|
|
|
|
commentThreadId: threadId,
|
|
|
|
|
// isResolved: resolvedState?.active,
|
|
|
|
|
mode,
|
|
|
|
|
pageId,
|
|
|
|
|
});
|
2021-09-07 12:45:17 +00:00
|
|
|
dispatch(setIsNotificationsListVisible(false));
|
2021-06-23 15:42:07 +00:00
|
|
|
history.push(
|
|
|
|
|
`${commentThreadUrl.pathname}${commentThreadUrl.search}${commentThreadUrl.hash}`,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
dispatch(markNotificationAsReadRequest(id || (_id as string)));
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-09 14:32:17 +00:00
|
|
|
return (
|
2021-06-23 15:42:07 +00:00
|
|
|
<FlexContainer onClick={handleClick}>
|
|
|
|
|
<ProfileImageContainer>
|
|
|
|
|
<ProfileImage
|
|
|
|
|
side={25}
|
|
|
|
|
source={`/api/${UserApi.photoURL}/${authorUsername}`}
|
|
|
|
|
userName={displayName}
|
|
|
|
|
/>
|
|
|
|
|
{!isRead && <UnreadIndicator />}
|
|
|
|
|
</ProfileImageContainer>
|
2021-06-09 14:32:17 +00:00
|
|
|
<NotificationBodyContainer>
|
|
|
|
|
<div>
|
2021-08-13 04:58:42 +00:00
|
|
|
<b>{displayName}</b> {eventName.toLowerCase()} a comment on
|
|
|
|
|
<b> {applicationName}</b>
|
2021-06-09 14:32:17 +00:00
|
|
|
</div>
|
2021-06-23 15:42:07 +00:00
|
|
|
<Time>{moment(_createdAt).fromNow()}</Time>
|
2021-06-09 14:32:17 +00:00
|
|
|
</NotificationBodyContainer>
|
|
|
|
|
</FlexContainer>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function CommentThreadNotification(props: {
|
|
|
|
|
notification: AppsmithNotification;
|
|
|
|
|
}) {
|
|
|
|
|
const dispatch = useDispatch();
|
2021-06-23 15:42:07 +00:00
|
|
|
const {
|
|
|
|
|
_id: _notificationId,
|
|
|
|
|
commentThread,
|
|
|
|
|
createdAt,
|
|
|
|
|
creationTime,
|
2021-08-13 04:58:42 +00:00
|
|
|
event,
|
2021-06-23 15:42:07 +00:00
|
|
|
id: notificationId,
|
|
|
|
|
isRead,
|
|
|
|
|
} = props.notification;
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
_id,
|
|
|
|
|
applicationId,
|
|
|
|
|
applicationName,
|
|
|
|
|
authorName,
|
|
|
|
|
authorUsername,
|
|
|
|
|
id,
|
2021-07-02 06:04:36 +00:00
|
|
|
mode: modeFromThread,
|
|
|
|
|
orgId,
|
2021-06-23 15:42:07 +00:00
|
|
|
pageId,
|
|
|
|
|
resolvedState,
|
|
|
|
|
} = commentThread;
|
|
|
|
|
|
|
|
|
|
const commentThreadId = _id || id;
|
|
|
|
|
|
2021-07-02 06:04:36 +00:00
|
|
|
const handleClick = async () => {
|
|
|
|
|
const modeFromRole = await getModeFromUserRole(orgId);
|
|
|
|
|
const mode = getModeFromRoleAndDomain(modeFromRole, modeFromThread);
|
|
|
|
|
|
|
|
|
|
const commentThreadUrl = getCommentThreadURL({
|
|
|
|
|
applicationId,
|
|
|
|
|
commentThreadId,
|
|
|
|
|
isResolved: resolvedState?.active,
|
|
|
|
|
mode,
|
|
|
|
|
pageId,
|
|
|
|
|
});
|
2021-06-09 14:32:17 +00:00
|
|
|
|
2021-09-07 12:45:17 +00:00
|
|
|
dispatch(setIsNotificationsListVisible(false));
|
|
|
|
|
|
2021-06-09 14:32:17 +00:00
|
|
|
history.push(
|
|
|
|
|
`${commentThreadUrl.pathname}${commentThreadUrl.search}${commentThreadUrl.hash}`,
|
|
|
|
|
);
|
|
|
|
|
|
2021-06-23 15:42:07 +00:00
|
|
|
dispatch(
|
|
|
|
|
markNotificationAsReadRequest(
|
|
|
|
|
notificationId || (_notificationId as string),
|
|
|
|
|
),
|
|
|
|
|
);
|
2021-06-09 14:32:17 +00:00
|
|
|
};
|
|
|
|
|
|
2021-06-23 15:42:07 +00:00
|
|
|
const _createdAt = createdAt || creationTime;
|
|
|
|
|
const displayName = authorName || authorUsername;
|
2021-08-13 04:58:42 +00:00
|
|
|
const eventName = event || "updated";
|
2021-06-09 14:32:17 +00:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<FlexContainer onClick={handleClick}>
|
|
|
|
|
<ProfileImageContainer>
|
|
|
|
|
<ProfileImage
|
|
|
|
|
side={25}
|
2021-06-23 15:42:07 +00:00
|
|
|
source={`/api/${UserApi.photoURL}/${authorUsername}`}
|
|
|
|
|
userName={displayName}
|
2021-06-09 14:32:17 +00:00
|
|
|
/>
|
|
|
|
|
{!isRead && <UnreadIndicator />}
|
|
|
|
|
</ProfileImageContainer>
|
|
|
|
|
<NotificationBodyContainer>
|
|
|
|
|
<div>
|
2021-08-13 04:58:42 +00:00
|
|
|
<b>{displayName}</b> {eventName.toLowerCase()} a thread on
|
|
|
|
|
<b> {applicationName}</b>
|
2021-06-09 14:32:17 +00:00
|
|
|
</div>
|
2021-06-23 15:42:07 +00:00
|
|
|
<Time>{moment(_createdAt).fromNow()}</Time>
|
2021-06-09 14:32:17 +00:00
|
|
|
</NotificationBodyContainer>
|
|
|
|
|
</FlexContainer>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const notificationByType = {
|
|
|
|
|
[NotificationTypes.CommentNotification]: CommentNotification,
|
|
|
|
|
[NotificationTypes.CommentThreadNotification]: CommentThreadNotification,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function NotificationListItem(props: { notification: AppsmithNotification }) {
|
2021-06-23 15:42:07 +00:00
|
|
|
// TODO fix this, use type from api response
|
|
|
|
|
const type = props.notification.comment
|
|
|
|
|
? NotificationTypes.CommentNotification
|
|
|
|
|
: NotificationTypes.CommentThreadNotification;
|
|
|
|
|
|
|
|
|
|
const Component = notificationByType[type];
|
2021-06-09 14:32:17 +00:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Container>
|
|
|
|
|
<Component notification={props.notification} />
|
|
|
|
|
</Container>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default NotificationListItem;
|