Skip to content

Commit

Permalink
perf(engage): updated manual engage, added engage notification count
Browse files Browse the repository at this point in the history
  • Loading branch information
Daarii committed Mar 6, 2024
1 parent 557b95b commit 4a84007
Show file tree
Hide file tree
Showing 44 changed files with 603 additions and 362 deletions.
20 changes: 10 additions & 10 deletions packages/core-ui/src/modules/layout/components/Search.tsx
Expand Up @@ -9,15 +9,15 @@ import styled from 'styled-components';
import styledTS from 'styled-components-ts';

const MainContainer = styledTS<{ active?: boolean }>(styled.div)`
background-color: ${props =>
background-color: ${(props) =>
props.active ? colors.colorWhite : colors.bgMain};
border: 1px solid ${props =>
border: 1px solid ${(props) =>
props.active ? colors.borderDarker : colors.bgMain};
border-radius: 35px;
height: 32px;
position: relative;
transition: .3s all;
width: ${props => (props.active ? '280px' : '120px')};
width: ${(props) => (props.active ? '280px' : '120px')};
display: flex;
padding: 0 ${dimensions.unitSpacing}px;
align-items: center;
Expand Down Expand Up @@ -177,21 +177,21 @@ class Search extends React.Component<
document.removeEventListener('click', this.handleClickOutside, true);
}

handleClickOutside = event => {
handleClickOutside = (event) => {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
this.setState({ showInput: false });
}
};

renderTitle = module => {
renderTitle = (module) => {
let text = module;

if (module === 'conversationMessages') {
text = 'Conversations';
}

if (module === 'engageMessages') {
text = 'Campaigns';
text = 'Broadcast';
}

return <SearchTitle>{text}</SearchTitle>;
Expand Down Expand Up @@ -285,7 +285,7 @@ class Search extends React.Component<
{this.renderTitle(result.module)}

<List>
{result.items.map(item => this.renderItem(result.module, item))}
{result.items.map((item) => this.renderItem(result.module, item))}
</List>
</div>
);
Expand Down Expand Up @@ -313,7 +313,7 @@ class Search extends React.Component<

let totalItems = 0;

results.forEach(result => {
results.forEach((result) => {
totalItems += result.items.length;
});

Expand Down Expand Up @@ -345,13 +345,13 @@ class Search extends React.Component<
this.setState({ showInput: true });
};

closeInput = e => {
closeInput = (e) => {
e.stopPropagation();
this.setState({ showInput: false, searchValue: '' });
this.props.clearSearch();
};

handleInput = e => {
handleInput = (e) => {
this.setState({ searchValue: e.target.value });
};

Expand Down
Expand Up @@ -24,17 +24,17 @@ class PermissionRow extends React.Component<Props> {
const { permission, actions, removeItem } = this.props;

const permissionAction = filterActions(actions, permission.module).filter(
action => action.value === permission.action
(action) => action.value === permission.action,
);

return (
<tr key={permission._id}>
<td>
<Capitalize>
{permission.module === 'engages' ? 'Campaigns' : permission.module}
{permission.module === 'engages' ? 'Broadcast' : permission.module}
</Capitalize>
</td>
<td>{permissionAction.map(action => action.label)}</td>
<td>{permissionAction.map((action) => action.label)}</td>
<td>{permission.user ? permission.user.email : ''}</td>
<td>{permission.group ? permission.group.name : ''}</td>
<td>
Expand Down
31 changes: 31 additions & 0 deletions packages/erxes-ui/src/apolloClient.ts
Expand Up @@ -16,10 +16,41 @@ import addMergeKeyfieldPolicy from './add-merge-keyfield-policy';

const { REACT_APP_API_SUBSCRIPTION_URL, REACT_APP_API_URL } = getEnv();

async function fetchWithTimeout(
input: RequestInfo | URL,
init?: RequestInit | undefined,
) {
const timeout = init?.headers?.['x-timeout'] || 30_000;
const controller = new AbortController();
const id = setTimeout(() => controller.abort('Request timed out'), timeout);

try {
const response = await fetch(input, {
...init,
signal: controller.signal,
});
return response;
} catch (e) {
if (controller.signal.aborted) {
console.error(
`Request timed out. Client side timeout limit ${timeout}ms exceeded.`,
init,
);
throw new Error(controller.signal.reason || 'Request timed out');
} else {
throw e;
}
} finally {
clearTimeout(id);
}
}


// Create an http link:
const httpLink = createHttpLink({
uri: `${REACT_APP_API_URL}/graphql`,
credentials: 'include',
fetch: fetchWithTimeout,
});

// Error handler
Expand Down
Expand Up @@ -7,15 +7,15 @@ const notificationQueries = {
async clientPortalNotificationCount(
_root,
{ all }: { all: boolean },
{ models, cpUser }: IContext
{ models, cpUser }: IContext,
) {
if (!cpUser) {
throw new Error('You are not logged in');
}

const qry: { receiver: string; isRead?: boolean } = {
receiver: cpUser._id,
isRead: false
isRead: false,
};

if (all) {
Expand All @@ -35,16 +35,16 @@ const notificationQueries = {
search,
startDate,
endDate,
eventDataFilter
eventDataFilter,
},
{ models, cpUser }: IContext
{ models, cpUser }: IContext,
) {
if (!cpUser) {
throw new Error('You are not logged in');
}

const query: any = {
receiver: cpUser._id
receiver: cpUser._id,
};

if (requireRead) {
Expand All @@ -61,13 +61,13 @@ const notificationQueries = {

if (startDate) {
query.createdAt = {
$gte: new Date(startDate)
$gte: new Date(startDate),
};
}

if (endDate) {
query.createdAt = {
$lte: new Date(endDate)
$lte: new Date(endDate),
};
}

Expand All @@ -80,31 +80,31 @@ const notificationQueries = {
models.ClientPortalNotifications.find(query).sort({ createdAt: -1 }),
{
page,
perPage
}
perPage,
},
);
},

async clientPortalNotificationDetail(
_root,
{ _id },
{ models, cpUser }: IContext
{ models, cpUser }: IContext,
) {
if (!cpUser) {
throw new Error('You are not logged in');
}

const notification = await models.ClientPortalNotifications.findOne({
_id,
receiver: cpUser._id
receiver: cpUser._id,
});

if (!notification) {
throw new Error('Notification not found');
}

return notification;
}
},
};

export default notificationQueries;
19 changes: 19 additions & 0 deletions packages/plugin-clientportal-api/src/messageBroker.ts
Expand Up @@ -86,6 +86,24 @@ export const setupMessageConsumers = async () => {
},
);

consumeRPCQueue(
'clientportal:clientPortalEngageNotifications',
async ({ subdomain, data: { selector } }) => {
const models = await generateModels(subdomain);

console.log(
'clientportal:clientPortalEngageNotifications.count',
selector,
);
return {
data: await models.ClientPortalNotifications.find(
selector,
).countDocuments(),
status: 'success',
};
},
);

consumeQueue(
'clientportal:sendSMS',
async ({ subdomain, data: { to, content, type } }) => {
Expand All @@ -103,6 +121,7 @@ export const setupMessageConsumers = async () => {
* @param {String} data.link // notification link
* @param {Object} data.createdUser // user who created this notification
* @param {Boolean} data.isMobile // is mobile notification
* @param {String} data.groupId // notification group id, when it's group notification
*/
consumeQueue('clientportal:sendNotification', async ({ subdomain, data }) => {
const models = await generateModels(subdomain);
Expand Down
Expand Up @@ -5,18 +5,18 @@ import { IModels } from '../connectionResolver';
import {
cpNotificationSchema,
ICPNotification,
ICPNotificationDocument
ICPNotificationDocument,
} from './definitions/clientPortalNotifications';

export interface ICPNotificationModel extends Model<ICPNotificationDocument> {
markAsRead(ids: string[], userId?: string): void;
createNotification(
doc: ICPNotification,
createdUser?: string
createdUser?: string,
): Promise<ICPNotificationDocument>;
updateNotification(
_id: string,
doc: ICPNotification
doc: ICPNotification,
): Promise<ICPNotificationDocument>;
checkIfRead(userId: string, contentTypeId: string): Promise<boolean>;
removeNotification(_id: string, receiver: string): void;
Expand All @@ -37,7 +37,7 @@ export const loadNotificationClass = (models: IModels) => {
return models.ClientPortalNotifications.updateMany(
selector,
{ $set: { isRead: true } },
{ multi: true }
{ multi: true },
);
}

Expand All @@ -48,7 +48,7 @@ export const loadNotificationClass = (models: IModels) => {
const notification = await models.ClientPortalNotifications.findOne({
isRead: false,
receiver: userId,
contentTypeId
contentTypeId,
});

return notification ? false : true;
Expand All @@ -59,15 +59,15 @@ export const loadNotificationClass = (models: IModels) => {
*/
public static async createNotification(
doc: ICPNotification,
createdUserId: string
createdUserId: string,
) {
// if receiver is configured to get this notification
const user = await models.ClientPortalUsers.getUser({
_id: doc.receiver
_id: doc.receiver,
});

const config = user.notificationSettings.configs.find(
c => c.notifType === doc.notifType
(c) => c.notifType === doc.notifType,
);

// receiver disabled this notification
Expand All @@ -77,7 +77,7 @@ export const loadNotificationClass = (models: IModels) => {

return models.ClientPortalNotifications.create({
...doc,
createdUser: createdUserId
createdUser: createdUserId,
});
}

Expand Down
Expand Up @@ -9,6 +9,7 @@ export interface ICPNotification {
notifType?: 'engage' | 'system';
clientPortalId: string;
eventData?: any | null;
groupId?: string;
}

export interface ICPNotificationDocument extends ICPNotification, Document {
Expand All @@ -29,26 +30,29 @@ export const cpNotificationSchema = new Schema({
createdAt: field({
type: Date,
default: Date.now,
expires: 60 * 60 * 24 * 30 // 30 days
expires: 60 * 60 * 24 * 30, // 30 days
}),
isRead: field({
type: Boolean,
default: false
default: false,
}),
notifType: field({
type: String
type: String,
}),
clientPortalId: field({
type: String,
index: true
index: true,
}),
eventData: field({
type: Schema.Types.Mixed,
optional: true
})
optional: true,
}),
groupId: field({
type: String,
}),
});

cpNotificationSchema.index(
{ createdAt: 1, receiver: 1, clientPortalId: 1 },
{ expireAfterSeconds: 60 * 60 * 24 * 30 }
{ expireAfterSeconds: 60 * 60 * 24 * 30 },
);

0 comments on commit 4a84007

Please sign in to comment.