close
Skip to content

Commit 3ef81e1

Browse files
feat(content-sidebar): added support for active comment reply (#3134)
* feat(content-sidebar): added support for active comment reply * feat(content-sidebar): added support for active comment reply * feat(content-sidebar): added support for active comment reply * feat(content-sidebar): added support for active comment reply * feat(content-sidebar): added support for active comment reply * feat(content-sidebar): added support for active comment reply * feat(content-sidebar): added support for active comment reply
1 parent 476d739 commit 3ef81e1

11 files changed

Lines changed: 926 additions & 24 deletions

File tree

‎src/api/Feed.js‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,51 @@ class Feed extends Base {
462462
});
463463
}
464464

465+
/**
466+
* Fetches a comment for a file
467+
*
468+
* @param {BoxItem} file - The file to which the comment belongs to
469+
* @param {string} commentId - comment id
470+
* @param {Function} successCallback
471+
* @param {ErrorCallback} errorCallback
472+
* @return {Promise} - the file comments
473+
*/
474+
fetchThreadedComment(
475+
file: BoxItem,
476+
commentId: string,
477+
successCallback: (comment: Comment) => void,
478+
errorCallback: ErrorCallback,
479+
): Promise<?Comment> {
480+
const { id, permissions } = file;
481+
if (!id || !permissions) {
482+
throw getBadItemError();
483+
}
484+
485+
this.threadedCommentsAPI = new ThreadedCommentsAPI(this.options);
486+
return new Promise(resolve => {
487+
this.threadedCommentsAPI.getComment({
488+
commentId,
489+
errorCallback,
490+
fileId: id,
491+
permissions,
492+
successCallback: this.fetchThreadedCommentSuccessCallback.bind(this, resolve, successCallback),
493+
});
494+
});
495+
}
496+
497+
/**
498+
* Callback for successful fetch of a comment
499+
*
500+
* @param {Function} resolve - resolve function
501+
* @param {Function} successCallback - success callback
502+
* @param {Comment} comment - comment data
503+
* @return {void}
504+
*/
505+
fetchThreadedCommentSuccessCallback = (resolve: Function, successCallback: Function, comment: Comment): void => {
506+
successCallback(comment);
507+
resolve();
508+
};
509+
465510
/**
466511
* Fetches the comments with replies for a file
467512
*

‎src/api/ThreadedComments.js‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
ERROR_CODE_CREATE_COMMENT,
1313
ERROR_CODE_UPDATE_COMMENT,
1414
ERROR_CODE_DELETE_COMMENT,
15+
ERROR_CODE_FETCH_COMMENT,
1516
ERROR_CODE_FETCH_COMMENTS,
1617
PERMISSION_CAN_RESOLVE,
1718
ERROR_CODE_FETCH_REPLIES,
@@ -228,6 +229,45 @@ class ThreadedComments extends MarkerBasedApi {
228229
});
229230
}
230231

232+
/**
233+
* API for fetching comment
234+
*
235+
* @param {string} commentId - comment id
236+
* @param {string} fileId - the file id
237+
* @param {BoxItemPermission} permissions - the permissions for the file
238+
* @param {Function} successCallback - the success callback
239+
* @param {Function} errorCallback - the error callback
240+
* @returns {void}
241+
*/
242+
getComment({
243+
commentId,
244+
errorCallback,
245+
fileId,
246+
permissions,
247+
successCallback,
248+
}: {
249+
commentId: string,
250+
errorCallback: (e: ElementsXhrError, code: string) => void,
251+
fileId: string,
252+
permissions: BoxItemPermission,
253+
successCallback: (comment: Comment) => void,
254+
}): void {
255+
this.errorCode = ERROR_CODE_FETCH_COMMENT;
256+
try {
257+
this.checkApiCallValidity(PERMISSION_CAN_COMMENT, permissions, fileId);
258+
} catch (e) {
259+
errorCallback(e, this.errorCode);
260+
return;
261+
}
262+
263+
this.get({
264+
id: fileId,
265+
errorCallback,
266+
successCallback,
267+
url: this.getUrlForId(commentId),
268+
});
269+
}
270+
231271
/**
232272
* API for fetching comments
233273
*

‎src/api/__tests__/Feed.test.js‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ jest.mock('../Comments', () =>
203203

204204
jest.mock('../ThreadedComments', () =>
205205
jest.fn().mockImplementation(() => ({
206+
getComment: jest.fn().mockResolvedValue(mockThreadedComments[1]),
206207
getComments: jest.fn().mockReturnValue({
207208
entries: mockThreadedComments,
208209
limit: 1000,
@@ -627,6 +628,53 @@ describe('api/Feed', () => {
627628
});
628629
});
629630

631+
describe('fetchThreadedComment()', () => {
632+
test('should throw if no file id', () => {
633+
expect(() => feed.fetchThreadedComment({})).toThrow(fileError);
634+
});
635+
636+
test('should throw if no file permissions', () => {
637+
expect(() => feed.fetchReplies({ id: '1234' })).toThrow(fileError);
638+
});
639+
640+
test('should call the threaded comments api', () => {
641+
const commentId = '123';
642+
const successCallback = jest.fn();
643+
const errorCallback = jest.fn();
644+
const boundFetchThreadedCommentSuccessCallback = jest.fn();
645+
feed.fetchThreadedCommentSuccessCallback = jest.fn();
646+
feed.fetchThreadedCommentSuccessCallback.bind = jest.fn(() => boundFetchThreadedCommentSuccessCallback);
647+
648+
feed.fetchThreadedComment(file, commentId, successCallback, errorCallback);
649+
650+
expect(feed.threadedCommentsAPI.getComment).toBeCalledWith({
651+
commentId,
652+
errorCallback,
653+
fileId: file.id,
654+
permissions: file.permissions,
655+
successCallback: boundFetchThreadedCommentSuccessCallback,
656+
});
657+
expect(feed.fetchThreadedCommentSuccessCallback.bind).toBeCalledWith(
658+
feed,
659+
expect.any(Function),
660+
successCallback,
661+
);
662+
});
663+
});
664+
665+
describe('fetchThreadedCommentSuccessCallback()', () => {
666+
test('should call successCallback with given comment and call resolve function', () => {
667+
const comment = { id: '123' };
668+
const successCallback = jest.fn();
669+
const resolve = jest.fn();
670+
671+
feed.fetchThreadedCommentSuccessCallback(resolve, successCallback, comment);
672+
673+
expect(successCallback).toBeCalledWith(comment);
674+
expect(resolve).toBeCalledWith();
675+
});
676+
});
677+
630678
describe('fetchThreadedComments()', () => {
631679
beforeEach(() => {
632680
feed.file = file;

‎src/api/__tests__/ThreadedComments.test.js‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ERROR_CODE_CREATE_COMMENT,
55
ERROR_CODE_UPDATE_COMMENT,
66
ERROR_CODE_DELETE_COMMENT,
7+
ERROR_CODE_FETCH_COMMENT,
78
ERROR_CODE_FETCH_COMMENTS,
89
ERROR_CODE_FETCH_REPLIES,
910
ERROR_CODE_CREATE_REPLY,
@@ -191,6 +192,51 @@ describe('api/ThreadedComments', () => {
191192
});
192193
});
193194

195+
describe('getComment()', () => {
196+
const errorCallback = jest.fn();
197+
const successCallback = jest.fn();
198+
199+
test('should format its parameters and call the get method', () => {
200+
const permissions = {
201+
can_comment: true,
202+
};
203+
const url = 'http://test-url.com';
204+
205+
threadedComments.getUrlForId = jest.fn().mockImplementationOnce(() => url);
206+
207+
threadedComments.getComment({
208+
commentId: '123',
209+
fileId: '12345',
210+
permissions,
211+
successCallback,
212+
errorCallback,
213+
});
214+
215+
expect(threadedComments.get).toBeCalledWith({
216+
id: '12345',
217+
errorCallback,
218+
successCallback,
219+
url,
220+
});
221+
});
222+
223+
test('should reject with an error code for calls with invalid permissions', () => {
224+
const permissions = {
225+
can_comment: false,
226+
};
227+
threadedComments.getComment({
228+
commentId: '123',
229+
fileId: '12345',
230+
permissions,
231+
successCallback,
232+
errorCallback,
233+
});
234+
235+
expect(errorCallback).toBeCalledWith(expect.any(Error), ERROR_CODE_FETCH_COMMENT);
236+
expect(threadedComments.get).not.toBeCalled();
237+
});
238+
});
239+
194240
describe('getComments()', () => {
195241
const errorCallback = jest.fn();
196242
const successCallback = jest.fn();

‎src/common/types/feed.js‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@ import {
66
FEED_ITEM_TYPE_ANNOTATION,
77
FEED_ITEM_TYPE_APP_ACTIVITY,
88
FEED_ITEM_TYPE_COMMENT,
9+
FEED_ITEM_TYPE_VERSION,
910
FEED_ITEM_TYPE_TASK,
1011
} from '../../constants';
1112
import type { BoxItemPermission, BoxItemVersion, Reply, User } from './core';
1213
import type { Annotation, AnnotationPermission, Annotations } from './annotations';
1314

15+
type FeedItemType =
16+
| typeof FEED_ITEM_TYPE_ANNOTATION
17+
| typeof FEED_ITEM_TYPE_APP_ACTIVITY
18+
| typeof FEED_ITEM_TYPE_COMMENT
19+
| typeof FEED_ITEM_TYPE_VERSION
20+
| typeof FEED_ITEM_TYPE_TASK;
21+
1422
// Feed item types that can receive deeplinks inline in the feed
1523
type FocusableFeedItemType =
1624
| typeof FEED_ITEM_TYPE_TASK
@@ -128,6 +136,10 @@ type FeedItem = Annotation | Comment | Task | BoxItemVersion | AppActivityItem;
128136

129137
type FeedItems = Array<FeedItem>;
130138

139+
type FocusableFeedItem = Annotation | Comment | Task;
140+
141+
type CommentFeedItem = Annotation | Comment;
142+
131143
type ActionItemError = {
132144
action?: {
133145
onAction: () => void,
@@ -150,11 +162,14 @@ export type {
150162
AppItem,
151163
BoxCommentPermission,
152164
Comment,
165+
CommentFeedItem,
153166
CommentFeedItemType,
154167
Comments,
155168
FeedItem,
156169
FeedItems,
157170
FeedItemStatus,
171+
FeedItemType,
172+
FocusableFeedItem,
158173
FocusableFeedItemType,
159174
Reply,
160175
Task,

‎src/constants.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ export const ERROR_CODE_FETCH_FILE_DUE_TO_POLICY = 'forbidden_by_policy';
250250
export const ERROR_CODE_FETCH_FOLDER = 'fetch_folder_error';
251251
export const ERROR_CODE_FETCH_WEBLINK = 'fetch_weblink_error';
252252
export const ERROR_CODE_FETCH_CLASSIFICATION = 'fetch_classification_error';
253+
export const ERROR_CODE_FETCH_COMMENT = 'fetch_comment_error';
253254
export const ERROR_CODE_FETCH_COMMENTS = 'fetch_comments_error';
254255
export const ERROR_CODE_FETCH_REPLIES = 'fetch_replies_error';
255256
export const ERROR_CODE_FETCH_VERSION = 'fetch_version_error';

0 commit comments

Comments
 (0)