Skip to content

Commit f9f04f3

Browse files
authored
Merge pull request #21 from Acode-Foundation/fix-comment
feat(plugin): add PluginStatus component for managing plugin status d…
2 parents bac674b + e0a2fe9 commit f9f04f3

File tree

5 files changed

+100
-56
lines changed

5 files changed

+100
-56
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"gapis",
4141
"hangingpiece",
4242
"hideloading",
43+
"hilightjs",
4344
"hintrc",
4445
"hljs",
4546
"iconsrc",

client/components/pluginStatus.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { capitalize, getLoggedInUser, hideLoading, showLoading } from 'lib/helpers';
2+
import alert from './dialogs/alert';
3+
import prompt from './dialogs/prompt';
4+
import select from './dialogs/select';
5+
6+
/**
7+
*
8+
* @param {object} props
9+
* @param {string} props.status
10+
* @param {string} props.id
11+
* @param {'default'|'button'} [props.style]
12+
* @returns
13+
*/
14+
export default async function PluginStatus({ status, id, style = 'default' }) {
15+
if (!status) return null;
16+
const { isAdmin } = (await getLoggedInUser()) || {};
17+
18+
if (style === 'button') {
19+
return (
20+
<button
21+
type='button'
22+
data-id={id}
23+
onclick={isAdmin ? changePluginStatus : undefined}
24+
title='Plugin status'
25+
className={`status-button ${status}`}
26+
>
27+
{capitalize(status)}
28+
</button>
29+
);
30+
}
31+
32+
return (
33+
<span data-id={id} onclick={isAdmin ? changePluginStatus : undefined} title='Plugin status' className={`status-indicator ${status}`}>
34+
{status}
35+
</span>
36+
);
37+
}
38+
39+
/**
40+
*
41+
* @param {MouseEvent} e
42+
* @returns
43+
*/
44+
async function changePluginStatus(e) {
45+
e.preventDefault();
46+
e.stopPropagation();
47+
try {
48+
const { target } = e;
49+
const { id } = target.dataset;
50+
const status = await select('Change plugin status', ['approve', 'reject']);
51+
if (!status) return;
52+
53+
let reason;
54+
if (status === 'reject') {
55+
reason = await prompt('Reason', { type: 'textarea' });
56+
}
57+
showLoading();
58+
const res = await fetch('/api/plugin', {
59+
method: 'PATCH',
60+
headers: {
61+
'Content-Type': 'application/json',
62+
},
63+
body: JSON.stringify({ status, id, reason }),
64+
});
65+
const data = await res.json();
66+
if (data.error) {
67+
alert('Error', data.error);
68+
return;
69+
}
70+
71+
const pluginRes = await fetch(`/api/plugin/${id}`);
72+
const pluginData = await pluginRes.json();
73+
target.textContent = capitalize(pluginData.status);
74+
target.className = pluginData.status;
75+
} catch (error) {
76+
alert('Error', error.message);
77+
} finally {
78+
hideLoading();
79+
}
80+
}

client/components/plugins/index.js

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import './style.scss';
22
import AdSense from 'components/adsense';
33
import alert from 'components/dialogs/alert';
44
import confirm from 'components/dialogs/confirm';
5-
import prompt from 'components/dialogs/prompt';
65
import select from 'components/dialogs/select';
7-
import { calcRating, capitalize, getLoggedInUser, hideLoading, showLoading, since } from 'lib/helpers';
6+
import PluginStatus from 'components/pluginStatus';
7+
import { calcRating, getLoggedInUser, hideLoading, showLoading, since } from 'lib/helpers';
88
import Router from 'lib/Router';
99

1010
export default function Plugins({ user, orderBy, status, name }) {
@@ -75,11 +75,7 @@ function Plugin({
7575
<div title='Downloads counter'>
7676
{downloads.toLocaleString()} <span className='icon download' />
7777
</div>
78-
{Boolean(status) && (
79-
<span data-id={id} onclick={isAdmin ? changePluginStatus : undefined} title='Plugin status' className={`status-indicator ${status}`}>
80-
{status}
81-
</span>
82-
)}
78+
<PluginStatus status={status} id={id} />
8379
<div>{calcRating(upVotes, downVotes)}</div>
8480
{comments > 0 && (
8581
<div>
@@ -154,49 +150,6 @@ async function deletePlugin(e, id) {
154150
}
155151
}
156152

157-
/**
158-
*
159-
* @param {MouseEvent} e
160-
* @returns
161-
*/
162-
async function changePluginStatus(e) {
163-
e.preventDefault();
164-
e.stopPropagation();
165-
try {
166-
const { target } = e;
167-
const { id } = target.dataset;
168-
const status = await select('Change plugin status', ['approve', 'reject']);
169-
if (!status) return;
170-
171-
let reason;
172-
if (status === 'reject') {
173-
reason = await prompt('Reason', { type: 'textarea' });
174-
}
175-
showLoading();
176-
const res = await fetch('/api/plugin', {
177-
method: 'PATCH',
178-
headers: {
179-
'Content-Type': 'application/json',
180-
},
181-
body: JSON.stringify({ status, id, reason }),
182-
});
183-
const data = await res.json();
184-
if (data.error) {
185-
alert('Error', data.error);
186-
return;
187-
}
188-
189-
const pluginRes = await fetch(`/api/plugin/${id}`);
190-
const pluginData = await pluginRes.json();
191-
target.textContent = capitalize(pluginData.status);
192-
target.className = pluginData.status;
193-
} catch (error) {
194-
alert('Error', error.message);
195-
} finally {
196-
hideLoading();
197-
}
198-
}
199-
200153
function Actions({ user, pluginsUser, id, isAdmin }) {
201154
const $el = <small className='icon-buttons' />;
202155
const $delete = <span title='delete plugin' className='link icon delete danger' onclick={(e) => deletePlugin(e, id)} />;

client/pages/plugin/index.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import confirm from 'components/dialogs/confirm';
77
import prompt from 'components/dialogs/prompt';
88
import Input from 'components/input';
99
import MonthSelect from 'components/MonthSelect';
10+
import PluginStatus from 'components/pluginStatus';
1011
import YearSelect from 'components/YearSelect';
1112
import hilightjs from 'highlight.js';
1213
import Ref from 'html-tag-js/ref';
@@ -25,6 +26,7 @@ export default async function Plugin({ id: pluginId, section = 'description' })
2526
id,
2627
name,
2728
price,
29+
status,
2830
author,
2931
version,
3032
license,
@@ -97,6 +99,7 @@ export default async function Plugin({ id: pluginId, section = 'description' })
9799
<span className='icon download' /> Install
98100
</button>
99101
)}
102+
<PluginStatus status={status} id={id} style='button' />
100103
</div>
101104
<div className='info-container'>
102105
<div className='info'>
@@ -392,8 +395,9 @@ function CommentsContainerAndForm({ plugin, listRef, user, id, userComment }) {
392395
);
393396
}
394397

395-
const { comment, vote, id: commentId } = userComment;
398+
const { comment, vote } = userComment;
396399
const form = Ref();
400+
let commentId = userComment.id;
397401

398402
return (
399403
<div className='comments'>
@@ -428,6 +432,7 @@ function CommentsContainerAndForm({ plugin, listRef, user, id, userComment }) {
428432

429433
let $comment;
430434

435+
commentId = commentId || res.id;
431436
if (commentId) {
432437
userComment = await fetch(`/api/comment/${commentId}`).then((userRes) => userRes.json());
433438
$comment = tag.get(`#comment_${commentId}`);
@@ -572,8 +577,13 @@ async function flagComment(id, flagRef) {
572577
}
573578
}
574579

575-
async function getUserComment(id) {
576-
const res = await fetch(`/api/user/comment/${id}`).then((commentRes) => commentRes.json());
580+
/**
581+
* Gets the current user's comment for a specific plugin.
582+
* @param {string} pluginId Plugin ID
583+
* @returns {Promise<Object>} The user's comment for the specified plugin.
584+
*/
585+
async function getUserComment(pluginId) {
586+
const res = await fetch(`/api/user/comment/${pluginId}`).then((commentRes) => commentRes.json());
577587
return res;
578588
}
579589

server/apis/comment.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ router.post('/', async (req, res) => {
126126

127127
if (updates.length) {
128128
await Comment.update(updates, [Comment.ID, alreadyVoted.id]);
129-
res.send({ message: 'Comment updated' });
129+
res.send({ message: 'Comment updated', id: alreadyVoted.id, comment, vote });
130130
if (isVoteChanged) {
131131
updateVoteInPlugin(vote, pluginId);
132132
}
@@ -136,7 +136,7 @@ router.post('/', async (req, res) => {
136136
return;
137137
}
138138

139-
res.send({ message: 'Comment unchanged' });
139+
res.send({ message: 'Comment unchanged', id: alreadyVoted.id, comment: alreadyVoted.comment, vote: alreadyVoted.vote });
140140
return;
141141
}
142142

@@ -150,7 +150,7 @@ router.post('/', async (req, res) => {
150150
if (vote !== Comment.VOTE_NULL) {
151151
updateVoteInPlugin(vote, pluginId);
152152
}
153-
res.send({ message: 'Comment added', comment: row });
153+
res.send({ message: 'Comment added', id: row.id, comment, vote });
154154
voteMessage = vote !== Comment.VOTE_NULL ? `${loggedInUser.name} voted ${Comment.getVoteString(vote)}` : '';
155155
commentMessage = comment ? `${loggedInUser.name} commented: ${comment}` : '';
156156
sendEmail(plugin.author_email, plugin.author, `New review for your Acode plugin - ${plugin.name}.`, getNotificationMessage());

0 commit comments

Comments
 (0)