@kiva/kv-components 3.55.0 → 3.55.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,25 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [3.55.2](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.55.1...@kiva/kv-components@3.55.2) (2024-03-01)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * remove const var import ([#352](https://github.com/kiva/kv-ui-elements/issues/352)) ([4c1ca6a](https://github.com/kiva/kv-ui-elements/commit/4c1ca6a2d518ce1b1b72933b5f5296513d352fa2))
12
+
13
+
14
+
15
+
16
+
17
+ ## [3.55.1](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.55.0...@kiva/kv-components@3.55.1) (2024-02-29)
18
+
19
+ **Note:** Version bump only for package @kiva/kv-components
20
+
21
+
22
+
23
+
24
+
6
25
  # [3.55.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.54.0...@kiva/kv-components@3.55.0) (2024-02-29)
7
26
 
8
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kiva/kv-components",
3
- "version": "3.55.0",
3
+ "version": "3.55.2",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -75,5 +75,5 @@
75
75
  "optional": true
76
76
  }
77
77
  },
78
- "gitHead": "ecd01faa5db8db12e79b243f311a264616a23e7d"
78
+ "gitHead": "a4e1a58a5c50681cca58459149abcb88ba99d572"
79
79
  }
@@ -16,26 +16,151 @@ const comments = {
16
16
  created_at: '2024-02-01T20:12:31.398932Z',
17
17
  updated_at: '2024-02-01T20:12:31.398932Z',
18
18
  id: 'dade3812-6aa0-4c32-90ea-2366dab178a1',
19
- user_id: '1de650a5-b12f-4d20-b46c-6e15b0722141',
20
19
  kind: 'comment',
21
20
  activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
22
21
  data: {
23
22
  text: 'another guest comment',
24
23
  },
24
+ user: {
25
+ data: {
26
+ publicLenderId: 'Nathan2352',
27
+ name: 'Nathan',
28
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
29
+ },
30
+ },
25
31
  parent: '',
26
- latest_children: {},
32
+ latest_children: {
33
+ like: [
34
+ {
35
+ created_at: '2024-02-28T20:04:21.445272Z',
36
+ updated_at: '2024-02-28T20:04:21.445272Z',
37
+ id: '290a6c07-143a-416e-b016-ac0d9ac8ad91',
38
+ user: {
39
+ created_at: '2024-02-28T19:09:54.093757Z',
40
+ updated_at: '2024-02-28T19:09:54.093757Z',
41
+ data: {
42
+ publicLenderId: 'Jess1234',
43
+ name: 'Jess',
44
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
45
+ },
46
+ },
47
+ kind: 'like',
48
+ activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
49
+ data: {},
50
+ parent: '6384df77-d7c4-4ea9-b1b9-ef1c76a054a2',
51
+ latest_children: {},
52
+ children_counts: {},
53
+ },
54
+ ],
55
+ comment: [
56
+ {
57
+ created_at: '2024-02-28T20:04:21.445272Z',
58
+ updated_at: '2024-02-28T20:04:21.445272Z',
59
+ id: '290a6c07-143a-416e-b016-ac0d9ac8ad92',
60
+ user: {
61
+ data: {
62
+ publicLenderId: 'Casey1234',
63
+ name: 'Casey',
64
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
65
+ },
66
+ },
67
+ kind: 'comment',
68
+ activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
69
+ data: {
70
+ text: 'child comment',
71
+ },
72
+ parent: '6384df77-d7c4-4ea9-b1b9-ef1c76a054a2',
73
+ latest_children: {
74
+ comment: [
75
+ {
76
+ created_at: '2024-02-28T20:04:21.445272Z',
77
+ updated_at: '2024-02-28T20:04:21.445272Z',
78
+ id: '290a6c07-143a-416e-b016-ac0d9ac8ad93',
79
+ user: {
80
+ data: {
81
+ publicLenderId: 'Sarah1234',
82
+ name: 'Sarah',
83
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
84
+ },
85
+ },
86
+ kind: 'comment',
87
+ activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
88
+ data: {
89
+ text: 'child comment reply',
90
+ },
91
+ parent: '6384df77-d7c4-4ea9-b1b9-ef1c76a054a2',
92
+ latest_children: {},
93
+ children_counts: {},
94
+ },
95
+ ],
96
+ },
97
+ children_counts: {},
98
+ },
99
+ {
100
+ created_at: '2024-02-28T20:04:21.445272Z',
101
+ updated_at: '2024-02-28T20:04:21.445272Z',
102
+ id: '290a6c07-143a-416e-b016-ac0d9ac8ad90',
103
+ user: {
104
+ data: {
105
+ publicLenderId: 'Sophie1234',
106
+ name: 'Sophie',
107
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
108
+ },
109
+ },
110
+ kind: 'comment',
111
+ activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
112
+ data: {
113
+ text: 'second child comment',
114
+ },
115
+ parent: '6384df77-d7c4-4ea9-b1b9-ef1c76a054a2',
116
+ latest_children: {
117
+ like: [
118
+ {
119
+ created_at: '2024-02-28T20:04:21.445272Z',
120
+ updated_at: '2024-02-28T20:04:21.445272Z',
121
+ id: '290a6c07-143a-416e-b016-ac0d9ac8ad99',
122
+ user: {
123
+ created_at: '2024-02-28T19:09:54.093757Z',
124
+ updated_at: '2024-02-28T19:09:54.093757Z',
125
+ data: {
126
+ publicLenderId: 'Jess1234',
127
+ name: 'Jess',
128
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
129
+ },
130
+ },
131
+ kind: 'like',
132
+ activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
133
+ data: {},
134
+ parent: '6384df77-d7c4-4ea9-b1b9-ef1c76a054a2',
135
+ latest_children: {},
136
+ children_counts: {},
137
+ },
138
+ ],
139
+ },
140
+ children_counts: {},
141
+ },
142
+ ],
143
+ },
27
144
  children_counts: {},
28
145
  },
29
146
  {
30
147
  created_at: '2024-02-01T20:11:23.931133Z',
31
148
  updated_at: '2024-02-01T20:11:23.931133Z',
32
149
  id: '3de615bb-0d48-4a69-9004-141ee26985eb',
33
- user_id: '1de650a5-b12f-4d20-b46c-6e15b0722141',
34
150
  kind: 'comment',
35
151
  activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
36
152
  data: {
37
153
  text: 'test as visitor',
38
154
  },
155
+ user: {
156
+ created_at: '2024-02-28T19:09:54.093757Z',
157
+ updated_at: '2024-02-28T19:09:54.093757Z',
158
+ data: {
159
+ publicLenderId: 'Lauren1234',
160
+ name: '',
161
+ image: '',
162
+ },
163
+ },
39
164
  parent: '',
40
165
  latest_children: {},
41
166
  children_counts: {},
@@ -45,17 +170,19 @@ const comments = {
45
170
  created_at: '2024-02-01T20:06:46.651764Z',
46
171
  updated_at: '2024-02-01T20:06:46.651764Z',
47
172
  id: 'e1db4420-159e-4ba2-aab9-704d1cc56dae',
48
- user_id: '123',
49
173
  user: {
50
- created_at: '2024-02-01T19:48:26.890734Z',
51
- updated_at: '2024-02-01T19:48:26.890734Z',
52
- id: '123',
53
- data: {},
174
+ created_at: '2024-02-28T19:09:54.093757Z',
175
+ updated_at: '2024-02-28T19:09:54.093757Z',
176
+ data: {
177
+ publicLenderId: 'Todd1234',
178
+ name: 'Todd',
179
+ image: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg', // eslint-disable-line max-len
180
+ },
54
181
  },
55
182
  kind: 'comment',
56
183
  activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
57
184
  data: {
58
- text: 'asd',
185
+ text: 'comment test forever!',
59
186
  },
60
187
  parent: '',
61
188
  latest_children: {},
@@ -9,7 +9,7 @@ const renderCommentsAdd = (props = {}) => {
9
9
  describe('KvCommentsAdd', () => {
10
10
  it('should render defaults', () => {
11
11
  const { getByPlaceholderText, getByRole } = renderCommentsAdd();
12
- getByPlaceholderText('Add a comment to this loan...');
12
+ getByPlaceholderText('Add a comment...');
13
13
  getByRole('button', { name: 'Cancel' });
14
14
  getByRole('button', { name: 'Comment' });
15
15
  });
@@ -25,7 +25,7 @@ describe('KvCommentsAdd', () => {
25
25
 
26
26
  it('should enable comment button when text entered', async () => {
27
27
  const { getByPlaceholderText, getByRole } = renderCommentsAdd();
28
- const textInput = getByPlaceholderText('Add a comment to this loan...');
28
+ const textInput = getByPlaceholderText('Add a comment...');
29
29
  const commentButton = getByRole('button', { name: 'Comment' });
30
30
 
31
31
  expect(commentButton.disabled).toBeTruthy();
@@ -41,7 +41,7 @@ describe('KvCommentsAdd', () => {
41
41
 
42
42
  it('should clear text when cancel clicked', async () => {
43
43
  const { getByPlaceholderText, getByRole } = renderCommentsAdd();
44
- const textInput = getByPlaceholderText('Add a comment to this loan...');
44
+ const textInput = getByPlaceholderText('Add a comment...');
45
45
  const cancelButton = getByRole('button', { name: 'Cancel' });
46
46
 
47
47
  await userEvent.type(textInput, 'test');
@@ -52,7 +52,7 @@ describe('KvCommentsAdd', () => {
52
52
 
53
53
  it('should emit value when comment clicked', async () => {
54
54
  const { getByPlaceholderText, getByRole, emitted } = renderCommentsAdd();
55
- const textInput = getByPlaceholderText('Add a comment to this loan...');
55
+ const textInput = getByPlaceholderText('Add a comment...');
56
56
  const commentButton = getByRole('button', { name: 'Comment' });
57
57
  const TEST_INPUT = 'test test';
58
58
 
@@ -63,6 +63,18 @@ describe('KvCommentsAdd', () => {
63
63
  expect(emitted()[ADD_COMMENT_EVENT]).toEqual([[TEST_INPUT]]);
64
64
  });
65
65
 
66
+ it('should emit value when enter key pressed', async () => {
67
+ const { getByPlaceholderText, emitted } = renderCommentsAdd();
68
+ const textInput = getByPlaceholderText('Add a comment...');
69
+ const TEST_INPUT = 'test test';
70
+
71
+ await userEvent.type(textInput, TEST_INPUT);
72
+
73
+ userEvent.keyboard('{enter}');
74
+
75
+ expect(emitted()[ADD_COMMENT_EVENT]).toEqual([[TEST_INPUT]]);
76
+ });
77
+
66
78
  it('should not emit empty value when comment clicked', async () => {
67
79
  const { getByRole, emitted } = renderCommentsAdd();
68
80
  const commentButton = getByRole('button', { name: 'Comment' });
@@ -74,7 +86,7 @@ describe('KvCommentsAdd', () => {
74
86
 
75
87
  it('should emit close event when it replies a comment', async () => {
76
88
  const { getByRole, emitted, getByPlaceholderText } = renderCommentsAdd({ isReply: true });
77
- const textInput = getByPlaceholderText('Add a comment to this loan...');
89
+ const textInput = getByPlaceholderText('Add a comment...');
78
90
  const commentButton = getByRole('button', { name: 'Comment' });
79
91
  const TEST_INPUT = 'test test';
80
92
 
@@ -1,6 +1,6 @@
1
1
  import { render } from '@testing-library/vue';
2
2
  import userEvent from '@testing-library/user-event';
3
- import Container from '../../../../vue/KvCommentsContainer.vue';
3
+ import Container, { ADD_REACTION_EVENT } from '../../../../vue/KvCommentsContainer.vue';
4
4
  import { ADD_COMMENT_ID, ADD_COMMENT_EVENT } from '../../../../vue/KvCommentsAdd.vue';
5
5
 
6
6
  const renderContainer = (props = {}) => {
@@ -15,7 +15,7 @@ describe('KvCommentsContainer', () => {
15
15
 
16
16
  it('should emit comment', async () => {
17
17
  const { getByPlaceholderText, getByRole, emitted } = renderContainer();
18
- const textInput = getByPlaceholderText('Add a comment to this loan...');
18
+ const textInput = getByPlaceholderText('Add a comment...');
19
19
  const commentButton = getByRole('button', { name: 'Comment' });
20
20
  const TEST_INPUT = 'test test';
21
21
 
@@ -23,6 +23,11 @@ describe('KvCommentsContainer', () => {
23
23
 
24
24
  await userEvent.click(commentButton);
25
25
 
26
- expect(emitted()[ADD_COMMENT_EVENT]).toEqual([[TEST_INPUT]]);
26
+ expect(emitted()[ADD_REACTION_EVENT]).toEqual([[{
27
+ id: null,
28
+ isChild: false,
29
+ reaction: ADD_COMMENT_EVENT,
30
+ value: TEST_INPUT,
31
+ }]]);
27
32
  });
28
33
  });
@@ -4,7 +4,7 @@ import KvCommentsHeartButton from '../../../../vue/KvCommentsHeartButton.vue';
4
4
 
5
5
  const CLICK_EVENT = 'click';
6
6
 
7
- describe('KvCommentsListItem', () => {
7
+ describe('KvCommentsHeartButton', () => {
8
8
  it('should render defaults', () => {
9
9
  const { getByRole } = render(KvCommentsHeartButton);
10
10
  const likeButton = getByRole('button', { name: 'Like' });
@@ -3,6 +3,7 @@ import userEvent from '@testing-library/user-event';
3
3
  import ListComponent from '../../../../vue/KvCommentsList.vue';
4
4
  import activityFeed from '../../../fixtures/mockFeedActivityData';
5
5
  import { LIKE_COMMENT_EVENT, REPLY_COMMENT_EVENT } from '../../../../vue/KvCommentsListItem.vue';
6
+ import { ADD_REACTION_EVENT } from '../../../../vue/KvCommentsContainer.vue';
6
7
 
7
8
  const renderList = (props = {}) => {
8
9
  return render(ListComponent, { props });
@@ -18,23 +19,44 @@ describe('KvCommentsList', () => {
18
19
  expect(container.querySelectorAll(`#${id}`).length).toBe(1);
19
20
  });
20
21
 
21
- it('should emit comment events', async () => {
22
- const { getAllByRole, getByRole, emitted } = renderList({ comments });
23
- const replyButton = getAllByRole('button', { name: 'Reply' })[0];
22
+ it('should emit like reaction events', async () => {
23
+ const { getAllByRole, emitted } = renderList({ comments });
24
24
  const likeButton = getAllByRole('button', { name: 'Like' })[0];
25
25
  const firstComment = comments.comment[0];
26
26
 
27
27
  const TEST_OBJ = {
28
- userId: firstComment.user_id,
28
+ id: firstComment.id,
29
+ isChild: true,
30
+ };
31
+
32
+ await userEvent.click(likeButton);
33
+ expect(emitted()[ADD_REACTION_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: LIKE_COMMENT_EVENT, value: true }]]);
34
+ });
35
+
36
+ it('should emit reply reaction events', async () => {
37
+ const {
38
+ getAllByRole,
39
+ getByRole,
40
+ getByPlaceholderText,
41
+ emitted,
42
+ } = renderList({ comments });
43
+ const replyButton = getAllByRole('button', { name: 'Reply' })[0];
44
+ const firstComment = comments.comment[0];
45
+
46
+ const TEST_OBJ = {
29
47
  id: firstComment.id,
30
48
  isChild: true,
31
49
  };
32
50
 
33
51
  await userEvent.click(replyButton);
34
- expect(emitted()[REPLY_COMMENT_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: REPLY_COMMENT_EVENT }]]);
35
- getByRole('button', { name: 'Comment' });
52
+ const commentButton = getByRole('button', { name: 'Comment' });
36
53
 
37
- await userEvent.click(likeButton);
38
- expect(emitted()[LIKE_COMMENT_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: LIKE_COMMENT_EVENT, value: true }]]);
54
+ const textInput = getByPlaceholderText('Add a comment...');
55
+ const TEST_INPUT = 'test test';
56
+
57
+ await userEvent.type(textInput, TEST_INPUT);
58
+
59
+ await userEvent.click(commentButton);
60
+ expect(emitted()[ADD_REACTION_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: REPLY_COMMENT_EVENT, value: TEST_INPUT }]]);
39
61
  });
40
62
  });
@@ -1,7 +1,8 @@
1
1
  import { render } from '@testing-library/vue';
2
2
  import userEvent from '@testing-library/user-event';
3
- import KvCommentsListItem, { LIKE_COMMENT_EVENT } from '../../../../vue/KvCommentsListItem.vue';
3
+ import KvCommentsListItem, { LIKE_COMMENT_EVENT, REPLY_COMMENT_EVENT } from '../../../../vue/KvCommentsListItem.vue';
4
4
  import activityFeed from '../../../fixtures/mockFeedActivityData';
5
+ import { ADD_REACTION_EVENT } from '../../../../vue/KvCommentsContainer.vue';
5
6
 
6
7
  const comment = activityFeed.results[0].latest_reactions.comment[0];
7
8
 
@@ -11,9 +12,12 @@ const renderComment = (props = {}) => {
11
12
 
12
13
  describe('KvCommentsListItem', () => {
13
14
  it('should render defaults', () => {
14
- const { getByRole } = renderComment({ comment });
15
- getByRole('button', { name: 'Reply' });
16
- getByRole('button', { name: 'Like' });
15
+ const { getAllByRole } = renderComment({ comment });
16
+ const replyButton = getAllByRole('button', { name: 'Reply' })[0];
17
+ const likeButton = getAllByRole('button', { name: 'Like' })[0];
18
+
19
+ expect(likeButton).toBeDefined();
20
+ expect(replyButton).toBeDefined();
17
21
  });
18
22
 
19
23
  it('should render comment text', () => {
@@ -22,25 +26,50 @@ describe('KvCommentsListItem', () => {
22
26
  });
23
27
 
24
28
  it('should handle like button click', async () => {
25
- const { getByRole, emitted } = renderComment({ comment });
26
- const likeButton = getByRole('button', { name: 'Like' });
29
+ const { getAllByRole, emitted } = renderComment({ comment });
30
+ const likeButton = getAllByRole('button', { name: 'Like' })[0];
27
31
 
28
32
  await userEvent.click(likeButton);
29
33
 
30
- expect(emitted()[LIKE_COMMENT_EVENT]).toEqual([[{
34
+ expect(emitted()[ADD_REACTION_EVENT]).toEqual([[{
31
35
  id: comment.id,
32
36
  isChild: true,
33
37
  reaction: LIKE_COMMENT_EVENT,
34
- userId: comment.user_id,
35
38
  value: true,
36
39
  }]]);
37
40
  });
38
41
 
39
42
  it('should handle reply button click', async () => {
40
- const { getByRole } = renderComment({ comment });
41
- const replyButton = getByRole('button', { name: 'Reply' });
43
+ const { getAllByRole, getByRole } = renderComment({ comment });
44
+ const replyButton = getAllByRole('button', { name: 'Reply' })[0];
42
45
 
43
46
  await userEvent.click(replyButton);
44
47
  getByRole('button', { name: 'Comment' });
45
48
  });
49
+
50
+ it('should emit reply reaction events', async () => {
51
+ const {
52
+ getAllByRole,
53
+ getByRole,
54
+ getByPlaceholderText,
55
+ emitted,
56
+ } = renderComment({ comment });
57
+ const replyButton = getAllByRole('button', { name: 'Reply' })[0];
58
+
59
+ const TEST_OBJ = {
60
+ id: comment.id,
61
+ isChild: true,
62
+ };
63
+
64
+ await userEvent.click(replyButton);
65
+ const commentButton = getByRole('button', { name: 'Comment' });
66
+
67
+ const textInput = getByPlaceholderText('Add a comment...');
68
+ const TEST_INPUT = 'test test';
69
+
70
+ await userEvent.type(textInput, TEST_INPUT);
71
+
72
+ await userEvent.click(commentButton);
73
+ expect(emitted()[ADD_REACTION_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: REPLY_COMMENT_EVENT, value: TEST_INPUT }]]);
74
+ });
46
75
  });
@@ -12,11 +12,11 @@ describe('KvCommentsReplyButton', () => {
12
12
  expect(replyButton).toBeDefined();
13
13
  });
14
14
 
15
- it('should emit true value when clicked as not liked', async () => {
15
+ it('should emit click event when clicked', async () => {
16
16
  const { getByRole, emitted } = render(KvCommentsReplyButton);
17
- const likeButton = getByRole('button', { name: 'Reply' });
17
+ const replyButton = getByRole('button', { name: 'Reply' });
18
18
 
19
- await userEvent.click(likeButton);
19
+ await userEvent.click(replyButton);
20
20
 
21
21
  expect(emitted()[CLICK_EVENT]).toEqual([[]]);
22
22
  });
@@ -24,8 +24,9 @@
24
24
  :id="ADD_COMMENT_ID"
25
25
  ref="input"
26
26
  v-model="addCommentValue"
27
- placeholder="Add a comment to this loan..."
27
+ placeholder="Add a comment..."
28
28
  class="data-hj-suppress tw-grow"
29
+ @keyup.enter="comment"
29
30
  />
30
31
  </div>
31
32
  <div class="tw-flex tw-py-0.5 tw-gap-0.5">
@@ -57,6 +58,7 @@ export const ADD_COMMENT_EVENT = 'add-comment';
57
58
  export const HIDE_INPUT_EVENT = 'hide-input';
58
59
 
59
60
  export default {
61
+ name: 'KvCommentsAdd',
60
62
  components: {
61
63
  KvButton,
62
64
  KvTextInput,
@@ -3,13 +3,15 @@
3
3
  <kv-comments-add
4
4
  :user-image-url="userImageUrl"
5
5
  :user-display-name="userDisplayName"
6
- @add-comment="comment"
6
+ @add-comment="handleReaction"
7
7
  />
8
8
  <kv-comments-list
9
9
  v-if="comments"
10
+ :user-image-url="userImageUrl"
11
+ :user-display-name="userDisplayName"
12
+ :user-public-id="userPublicId"
10
13
  :comments="comments"
11
- @[REPLY_COMMENT_EVENT]="comment"
12
- @[LIKE_COMMENT_EVENT]="comment"
14
+ @add-reaction="handleReaction"
13
15
  />
14
16
  </div>
15
17
  </template>
@@ -17,11 +19,12 @@
17
19
  <script>
18
20
  import KvCommentsAdd from './KvCommentsAdd.vue';
19
21
  import KvCommentsList from './KvCommentsList.vue';
20
- import { REPLY_COMMENT_EVENT, LIKE_COMMENT_EVENT } from './KvCommentsListItem.vue';
21
22
 
22
23
  export const ADD_COMMENT_EVENT = 'add-comment';
24
+ export const ADD_REACTION_EVENT = 'add-reaction';
23
25
 
24
26
  export default {
27
+ name: 'KvCommentsContainer',
25
28
  components: {
26
29
  KvCommentsAdd,
27
30
  KvCommentsList,
@@ -41,6 +44,13 @@ export default {
41
44
  type: String,
42
45
  default: '',
43
46
  },
47
+ /**
48
+ * The ID for the user
49
+ */
50
+ userPublicId: {
51
+ type: String,
52
+ default: '',
53
+ },
44
54
  /**
45
55
  * Activity comments
46
56
  */
@@ -49,16 +59,24 @@ export default {
49
59
  default: () => {},
50
60
  },
51
61
  },
62
+ emits: [ADD_REACTION_EVENT],
52
63
  setup(_props, { emit }) {
53
- const comment = (commentValue) => {
54
- emit(ADD_COMMENT_EVENT, commentValue);
55
- emit(REPLY_COMMENT_EVENT, commentValue);
56
- emit(LIKE_COMMENT_EVENT, commentValue);
64
+ const handleReaction = (reactionPayload) => {
65
+ let payload;
66
+ if (reactionPayload.value === undefined) {
67
+ payload = {
68
+ reaction: ADD_COMMENT_EVENT,
69
+ id: null,
70
+ isChild: false,
71
+ value: reactionPayload,
72
+ };
73
+ } else {
74
+ payload = reactionPayload;
75
+ }
76
+ emit(ADD_REACTION_EVENT, payload);
57
77
  };
58
78
  return {
59
- comment,
60
- REPLY_COMMENT_EVENT,
61
- LIKE_COMMENT_EVENT,
79
+ handleReaction,
62
80
  };
63
81
  },
64
82
  };
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <button
3
3
  aria-label="Like"
4
- @click="changeState"
4
+ class="tw-flex tw-flex-col tw-justify-center"
5
+ @click="$emit('click', !isLiked);"
5
6
  >
6
7
  <kv-material-icon
7
8
  :icon="icon"
@@ -39,7 +40,7 @@ export default {
39
40
  emits: [
40
41
  'click',
41
42
  ],
42
- setup(props, { emit }) {
43
+ setup(props) {
43
44
  const {
44
45
  isSmall,
45
46
  isLiked,
@@ -54,14 +55,9 @@ export default {
54
55
  return className;
55
56
  });
56
57
 
57
- const changeState = () => {
58
- emit('click', !isLiked.value);
59
- };
60
-
61
58
  return {
62
59
  icon,
63
60
  classState,
64
- changeState,
65
61
  };
66
62
  },
67
63
  };
@@ -6,20 +6,47 @@
6
6
  :key="comment.id"
7
7
  :nest-level="1"
8
8
  :comment="comment"
9
+ :user-image-url="userImageUrl"
10
+ :user-display-name="userDisplayName"
11
+ :user-public-id="userPublicId"
9
12
  :is-liked="comment.is_liked"
10
- @[REPLY_COMMENT_EVENT]="handleClick"
11
- @[LIKE_COMMENT_EVENT]="handleClick"
13
+ class="tw-mb-2"
14
+ @add-reaction="handleReaction"
12
15
  />
13
16
  </div>
14
17
  </template>
15
18
 
16
19
  <script>
17
20
 
18
- import KvCommentsListItem, { REPLY_COMMENT_EVENT, LIKE_COMMENT_EVENT } from './KvCommentsListItem.vue';
21
+ import KvCommentsListItem from './KvCommentsListItem.vue';
22
+
23
+ const ADD_REACTION_EVENT = 'add-reaction';
19
24
 
20
25
  export default {
26
+ name: 'KvCommentsList',
21
27
  components: { KvCommentsListItem },
22
28
  props: {
29
+ /**
30
+ * The full URL for the user image
31
+ */
32
+ userImageUrl: {
33
+ type: String,
34
+ default: '',
35
+ },
36
+ /**
37
+ * The name to display for the user
38
+ */
39
+ userDisplayName: {
40
+ type: String,
41
+ default: '',
42
+ },
43
+ /**
44
+ * The ID for the user
45
+ */
46
+ userPublicId: {
47
+ type: String,
48
+ default: '',
49
+ },
23
50
  /**
24
51
  * Activity comments
25
52
  */
@@ -28,15 +55,14 @@ export default {
28
55
  default: () => {},
29
56
  },
30
57
  },
58
+ emits: [ADD_REACTION_EVENT],
31
59
  setup(_props, { emit }) {
32
- const handleClick = (payload) => {
33
- emit(payload.reaction, { ...payload });
60
+ const handleReaction = (payload) => {
61
+ emit(ADD_REACTION_EVENT, payload);
34
62
  };
35
63
 
36
64
  return {
37
- handleClick,
38
- REPLY_COMMENT_EVENT,
39
- LIKE_COMMENT_EVENT,
65
+ handleReaction,
40
66
  };
41
67
  },
42
68
  };
@@ -1,24 +1,30 @@
1
1
  <template>
2
2
  <div>
3
- <div
4
- class="tw-flex tw-items-center tw-gap-1"
5
- >
6
- <img
7
- v-if="profileImage"
8
- class="
9
- data-hj-suppress
10
- tw-inline-block
11
- tw-w-3.5
12
- tw-h-3.5
13
- tw-rounded-full
14
- tw-overflow-hidden
15
- tw-object-fill
16
- "
17
- :src="profileImage"
18
- alt="picture"
19
- >
3
+ <div>
4
+ <div class="tw-flex tw-items-center tw-gap-1">
5
+ <img
6
+ v-if="authorImage"
7
+ class="
8
+ data-hj-suppress
9
+ tw-inline-block
10
+ tw-w-3.5
11
+ tw-h-3.5
12
+ tw-rounded-full
13
+ tw-overflow-hidden
14
+ tw-object-fill
15
+ "
16
+ :src="authorImage"
17
+ alt="picture"
18
+ >
19
+ <p
20
+ v-if="authorName"
21
+ class="tw-font-medium"
22
+ >
23
+ {{ authorName }}
24
+ </p>
25
+ </div>
20
26
  <p>
21
- {{ text }}
27
+ {{ commentText }}
22
28
  </p>
23
29
  </div>
24
30
  <div
@@ -28,10 +34,10 @@
28
34
  <kv-comments-heart-button
29
35
  :is-small="true"
30
36
  :is-liked="isLiked"
31
- @click="onClick(LIKE_COMMENT_EVENT, $event)"
37
+ @click="addReaction(LIKE_COMMENT_EVENT, $event)"
32
38
  />
33
39
  <kv-comments-reply-button
34
- @click="onClick(REPLY_COMMENT_EVENT, $event)"
40
+ @click="replyClick"
35
41
  />
36
42
  </div>
37
43
  <div
@@ -40,25 +46,30 @@
40
46
  >
41
47
  <kv-comments-add
42
48
  ref="commentsAddRef"
43
- user-mention
44
- @add-comment="onClick(REPLY_COMMENT_EVENT, $event)"
49
+ :user-image-url="userImageUrl"
50
+ :user-display-name="userDisplayName"
51
+ :is-reply="true"
52
+ class="tw-ml-3"
53
+ @add-comment="addReaction(REPLY_COMMENT_EVENT, $event)"
45
54
  @hide-input="hideInput"
46
55
  />
47
56
  </div>
48
57
  <div
49
- v-if="latestChildren"
58
+ v-if="childComments"
50
59
  class="tw-my-1"
51
60
  >
52
61
  <p
53
- v-for="nested_comment in latestChildren"
62
+ v-for="nested_comment in childComments"
54
63
  :key="nested_comment.id"
55
64
  class="tw-ml-3"
56
65
  >
57
66
  <kv-comments-list-item
67
+ :user-image-url="userImageUrl"
68
+ :user-display-name="userDisplayName"
69
+ :user-public-id="userPublicId"
58
70
  :comment="nested_comment"
59
- :is-liked="nested_comment.is_liked"
60
71
  :nest-level="nestLevel + 1"
61
- :handle-click="handleClick"
72
+ @add-reaction="$emit(ADD_REACTION_EVENT, $event);"
62
73
  />
63
74
  </p>
64
75
  </div>
@@ -66,13 +77,19 @@
66
77
  </template>
67
78
 
68
79
  <script>
69
- import { ref, nextTick } from 'vue-demi';
80
+ import {
81
+ ref,
82
+ nextTick,
83
+ computed,
84
+ toRefs,
85
+ } from 'vue-demi';
70
86
  import KvCommentsReplyButton from './KvCommentsReplyButton.vue';
71
87
  import KvCommentsHeartButton from './KvCommentsHeartButton.vue';
72
88
  import KvCommentsAdd from './KvCommentsAdd.vue';
73
89
 
74
90
  export const REPLY_COMMENT_EVENT = 'reply-comment';
75
91
  export const LIKE_COMMENT_EVENT = 'like-comment';
92
+ const ADD_REACTION_EVENT = 'add-reaction';
76
93
 
77
94
  export default {
78
95
  name: 'KvCommentsListItem',
@@ -82,6 +99,27 @@ export default {
82
99
  KvCommentsAdd,
83
100
  },
84
101
  props: {
102
+ /**
103
+ * The full URL for the user image
104
+ */
105
+ userImageUrl: {
106
+ type: String,
107
+ default: '',
108
+ },
109
+ /**
110
+ * The name to display for the user
111
+ */
112
+ userDisplayName: {
113
+ type: String,
114
+ default: '',
115
+ },
116
+ /**
117
+ * The ID for the user
118
+ */
119
+ userPublicId: {
120
+ type: String,
121
+ default: '',
122
+ },
85
123
  /**
86
124
  * Activity comment
87
125
  */
@@ -96,37 +134,46 @@ export default {
96
134
  type: Number,
97
135
  default: 0,
98
136
  },
99
- /**
100
- * Comment is liked by current user
101
- */
102
- isLiked: {
103
- type: Boolean,
104
- default: false,
105
- },
106
137
  },
107
138
  emits: [
108
- REPLY_COMMENT_EVENT,
109
- LIKE_COMMENT_EVENT,
139
+ ADD_REACTION_EVENT,
110
140
  ],
111
141
  setup(props, { emit }) {
142
+ const {
143
+ comment,
144
+ userPublicId,
145
+ } = toRefs(props);
146
+
112
147
  const showInput = ref(false);
113
148
  const commentsAddRef = ref(null);
114
149
 
115
- const onClick = (reaction, value) => {
116
- if (reaction === REPLY_COMMENT_EVENT) {
117
- showInput.value = true;
118
- nextTick(() => {
119
- commentsAddRef.value.$refs.input.focus();
120
- });
121
- }
150
+ const commentText = computed(() => comment?.value?.data?.text ?? '');
151
+ const authorImage = computed(() => comment?.value?.user?.data?.image ?? '');
152
+ const authorName = computed(() => comment?.value?.user?.data?.name ?? '');
153
+ const childComments = computed(() => comment?.value?.latest_children?.comment ?? null);
154
+ const childLikes = computed(() => comment?.value?.latest_children?.like ?? []);
155
+ const likedObject = computed(() => childLikes.value.find((child) => child.user.data.publicLenderId === userPublicId.value)); // eslint-disable-line max-len
156
+ const isLiked = computed(() => likedObject.value !== undefined);
122
157
 
123
- emit(reaction, {
158
+ const replyClick = () => {
159
+ showInput.value = !showInput.value;
160
+ nextTick(() => {
161
+ if (showInput.value) commentsAddRef.value.$refs.input.focus();
162
+ });
163
+ };
164
+
165
+ const addReaction = (reaction, value) => {
166
+ const payload = {
124
167
  reaction,
125
- id: props.comment?.id ?? null,
126
- userId: props.comment?.user_id ?? null,
168
+ id: comment?.value?.id ?? null,
127
169
  isChild: true,
128
170
  value,
129
- });
171
+ };
172
+ if (reaction === LIKE_COMMENT_EVENT && !value) {
173
+ payload.id = likedObject.value.id;
174
+ }
175
+
176
+ emit(ADD_REACTION_EVENT, payload);
130
177
  };
131
178
 
132
179
  const hideInput = () => { showInput.value = false; };
@@ -135,24 +182,17 @@ export default {
135
182
  hideInput,
136
183
  showInput,
137
184
  commentsAddRef,
138
- onClick,
185
+ replyClick,
186
+ addReaction,
139
187
  REPLY_COMMENT_EVENT,
140
188
  LIKE_COMMENT_EVENT,
189
+ ADD_REACTION_EVENT,
190
+ commentText,
191
+ authorImage,
192
+ authorName,
193
+ childComments,
194
+ isLiked,
141
195
  };
142
196
  },
143
- computed: {
144
- text() {
145
- return this.comment?.data?.text ?? '';
146
- },
147
- userId() {
148
- return this.comment?.user_id ?? null;
149
- },
150
- latestChildren() {
151
- return this.comment?.latest_children ?? null;
152
- },
153
- profileImage() {
154
- return this.comment?.user_picture ?? '';
155
- },
156
- },
157
197
  };
158
198
  </script>
@@ -1,10 +1,9 @@
1
1
  <!-- eslint-disable max-len -->
2
2
  <template>
3
3
  <button
4
- ref="replyButton"
5
4
  aria-label="Reply"
6
5
  class="tw-font-medium tw-flex tw-items-center tw-gap-x-0.5"
7
- @click="handleClick"
6
+ @click="$emit('click')"
8
7
  >
9
8
  <svg
10
9
  width="14"
@@ -26,24 +25,10 @@
26
25
  </template>
27
26
 
28
27
  <script>
29
- import { ref } from 'vue-demi';
30
-
31
28
  export default {
32
29
  name: 'KvCommentsReplyButton',
33
30
  emits: [
34
31
  'click',
35
32
  ],
36
- setup(_props, { emit }) {
37
- const replyButton = ref(null);
38
-
39
- const handleClick = () => {
40
- emit('click');
41
- };
42
-
43
- return {
44
- replyButton,
45
- handleClick,
46
- };
47
- },
48
33
  };
49
34
  </script>
@@ -1,5 +1,5 @@
1
1
  import KvCommentsContainer from '../KvCommentsContainer.vue';
2
- import comments from '../../tests/fixtures/mockFeedActivityData';
2
+ import activityFeed from '../../tests/fixtures/mockFeedActivityData';
3
3
 
4
4
  export default {
5
5
  title: 'KvCommentsContainer',
@@ -21,4 +21,15 @@ const story = (args) => {
21
21
  return template;
22
22
  };
23
23
 
24
+ const comments = activityFeed.results[0].latest_reactions;
25
+
24
26
  export const Default = story({ comments });
27
+
28
+ export const UserData = story(
29
+ {
30
+ comments,
31
+ userDisplayName: 'Jess',
32
+ userImageUrl: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg',
33
+ userPublicId: 'Jess1234',
34
+ },
35
+ );
@@ -22,3 +22,12 @@ const story = (args) => {
22
22
  const comments = activityFeed.results[0].latest_reactions;
23
23
 
24
24
  export const Default = story({ comments });
25
+
26
+ export const UserData = story(
27
+ {
28
+ comments,
29
+ userDisplayName: 'Jess',
30
+ userImageUrl: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg',
31
+ userPublicId: 'Jess1234',
32
+ },
33
+ );
@@ -19,6 +19,18 @@ const story = (args) => {
19
19
  return template;
20
20
  };
21
21
 
22
- const comment = activityFeed.results[0].latest_reactions.comment[0];
22
+ const comment = activityFeed.results[0].latest_reactions.comment[1];
23
+ const childComments = activityFeed.results[0].latest_reactions.comment[0];
23
24
 
24
25
  export const Default = story({ comment });
26
+
27
+ export const ChildComments = story({ comment: childComments });
28
+
29
+ export const UserData = story(
30
+ {
31
+ comment: childComments,
32
+ userDisplayName: 'Jess',
33
+ userImageUrl: 'https://www-0.development.kiva.org/img/s100/6b1a24092be3aaa22216874e644a4acf.jpg',
34
+ userPublicId: 'Jess1234',
35
+ },
36
+ );