mirror of
https://github.com/astuto/astuto.git
synced 2025-12-15 19:27:52 +01:00
Add setting to manage visibility of vote count, vote button and decide root page (#197)
This commit is contained in:
committed by
GitHub
parent
d4242dd78e
commit
e7335f5622
@@ -7,6 +7,7 @@ import PostList from './PostList';
|
||||
import Sidebar from '../common/Sidebar';
|
||||
|
||||
import IBoard from '../../interfaces/IBoard';
|
||||
import ITenantSetting from '../../interfaces/ITenantSetting';
|
||||
|
||||
import { PostsState } from '../../reducers/postsReducer';
|
||||
import { PostStatusesState } from '../../reducers/postStatusesReducer';
|
||||
@@ -14,6 +15,8 @@ import { PostStatusesState } from '../../reducers/postStatusesReducer';
|
||||
interface Props {
|
||||
board: IBoard;
|
||||
isLoggedIn: boolean;
|
||||
isPowerUser: boolean;
|
||||
tenantSetting: ITenantSetting;
|
||||
authenticityToken: string;
|
||||
posts: PostsState;
|
||||
postStatuses: PostStatusesState;
|
||||
@@ -63,6 +66,8 @@ class BoardP extends React.Component<Props> {
|
||||
const {
|
||||
board,
|
||||
isLoggedIn,
|
||||
isPowerUser,
|
||||
tenantSetting,
|
||||
authenticityToken,
|
||||
posts,
|
||||
postStatuses,
|
||||
@@ -97,6 +102,8 @@ class BoardP extends React.Component<Props> {
|
||||
|
||||
<PostList
|
||||
posts={posts.items}
|
||||
showLikeCount={isPowerUser || tenantSetting.show_vote_count}
|
||||
showLikeButtons={tenantSetting.show_vote_button_in_board}
|
||||
postStatuses={postStatuses.items}
|
||||
areLoading={posts.areLoading}
|
||||
error={posts.error}
|
||||
|
||||
@@ -14,6 +14,8 @@ import IPostStatus from '../../interfaces/IPostStatus';
|
||||
|
||||
interface Props {
|
||||
posts: Array<IPost>;
|
||||
showLikeCount: boolean;
|
||||
showLikeButtons: boolean;
|
||||
postStatuses: Array<IPostStatus>;
|
||||
areLoading: boolean;
|
||||
error: string;
|
||||
@@ -27,6 +29,8 @@ interface Props {
|
||||
|
||||
const PostList = ({
|
||||
posts,
|
||||
showLikeCount,
|
||||
showLikeButtons,
|
||||
postStatuses,
|
||||
areLoading,
|
||||
error,
|
||||
@@ -53,7 +57,9 @@ const PostList = ({
|
||||
title={post.title}
|
||||
description={post.description}
|
||||
postStatus={postStatuses.find(postStatus => postStatus.id === post.postStatusId)}
|
||||
likesCount={post.likesCount}
|
||||
likeCount={post.likeCount}
|
||||
showLikeCount={showLikeCount}
|
||||
showLikeButtons={showLikeButtons}
|
||||
liked={post.liked}
|
||||
commentsCount={post.commentsCount}
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@ interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
postStatus: IPostStatus;
|
||||
likesCount: number;
|
||||
likeCount: number;
|
||||
showLikeCount: boolean;
|
||||
showLikeButtons: boolean;
|
||||
liked: number;
|
||||
commentsCount: number;
|
||||
|
||||
@@ -25,7 +27,9 @@ const PostListItem = ({
|
||||
title,
|
||||
description,
|
||||
postStatus,
|
||||
likesCount,
|
||||
likeCount,
|
||||
showLikeCount,
|
||||
showLikeButtons,
|
||||
liked,
|
||||
commentsCount,
|
||||
|
||||
@@ -35,7 +39,9 @@ const PostListItem = ({
|
||||
<div onClick={() => window.location.href = `/posts/${id}`} className="postListItem">
|
||||
<LikeButton
|
||||
postId={id}
|
||||
likesCount={likesCount}
|
||||
likeCount={likeCount}
|
||||
showLikeCount={showLikeCount}
|
||||
showLikeButton={showLikeButtons}
|
||||
liked={liked}
|
||||
isLoggedIn={isLoggedIn}
|
||||
authenticityToken={authenticityToken}
|
||||
|
||||
@@ -8,10 +8,13 @@ import IBoard from '../../interfaces/IBoard';
|
||||
|
||||
import { Store } from 'redux';
|
||||
import { State } from '../../reducers/rootReducer';
|
||||
import ITenantSetting from '../../interfaces/ITenantSetting';
|
||||
|
||||
interface Props {
|
||||
board: IBoard;
|
||||
isLoggedIn: boolean;
|
||||
isPowerUser: boolean;
|
||||
tenantSetting: ITenantSetting;
|
||||
authenticityToken: string;
|
||||
}
|
||||
|
||||
@@ -25,13 +28,21 @@ class BoardRoot extends React.Component<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { board, isLoggedIn, authenticityToken } = this.props;
|
||||
const {
|
||||
board,
|
||||
isLoggedIn,
|
||||
isPowerUser,
|
||||
tenantSetting,
|
||||
authenticityToken,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Provider store={this.store}>
|
||||
<Board
|
||||
board={board}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isPowerUser={isPowerUser}
|
||||
tenantSetting={tenantSetting}
|
||||
authenticityToken={authenticityToken}
|
||||
/>
|
||||
</Provider>
|
||||
|
||||
@@ -2,7 +2,9 @@ import * as React from 'react';
|
||||
|
||||
interface Props {
|
||||
postId: number;
|
||||
likesCount: number;
|
||||
likeCount: number;
|
||||
showLikeCount?: boolean;
|
||||
showLikeButton?: boolean;
|
||||
liked: number;
|
||||
handleLikeSubmit(
|
||||
postId: number,
|
||||
@@ -15,7 +17,9 @@ interface Props {
|
||||
|
||||
const LikeButtonP = ({
|
||||
postId,
|
||||
likesCount,
|
||||
likeCount,
|
||||
showLikeCount = true,
|
||||
showLikeButton = true,
|
||||
liked,
|
||||
handleLikeSubmit,
|
||||
authenticityToken,
|
||||
@@ -29,9 +33,10 @@ const LikeButtonP = ({
|
||||
else window.location.href = `/users/sign_in`;
|
||||
}}
|
||||
className={`likeButton${liked ? ' liked' : ''}`}
|
||||
hidden={!showLikeButton}
|
||||
>
|
||||
</div>
|
||||
<span className="likesCountLabel">{likesCount}</span>
|
||||
{ showLikeCount && <span className="likeCountLabel">{likeCount}</span> }
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { getLabel } from '../../helpers/formUtils';
|
||||
|
||||
import IBoard from '../../interfaces/IBoard';
|
||||
|
||||
@@ -25,7 +26,7 @@ const PostBoardSelect = ({
|
||||
id="selectPickerBoard"
|
||||
className="selectPicker"
|
||||
>
|
||||
<optgroup label="Boards">
|
||||
<optgroup label={getLabel('board')}>
|
||||
{boards.map((board, i) => (
|
||||
<option value={board.id} key={i}>
|
||||
{board.name}
|
||||
|
||||
@@ -4,6 +4,7 @@ import ReactMarkdown from 'react-markdown';
|
||||
import IPost from '../../interfaces/IPost';
|
||||
import IPostStatus from '../../interfaces/IPostStatus';
|
||||
import IBoard from '../../interfaces/IBoard';
|
||||
import ITenantSetting from '../../interfaces/ITenantSetting';
|
||||
|
||||
import PostUpdateList from './PostUpdateList';
|
||||
import PostEditForm from './PostEditForm';
|
||||
@@ -39,6 +40,7 @@ interface Props {
|
||||
isPowerUser: boolean;
|
||||
currentUserFullName: string;
|
||||
currentUserEmail: string;
|
||||
tenantSetting: ITenantSetting;
|
||||
authenticityToken: string;
|
||||
|
||||
requestPost(postId: number): void;
|
||||
@@ -148,6 +150,7 @@ class PostP extends React.Component<Props> {
|
||||
isLoggedIn,
|
||||
isPowerUser,
|
||||
currentUserEmail,
|
||||
tenantSetting,
|
||||
authenticityToken,
|
||||
|
||||
submitFollow,
|
||||
@@ -176,11 +179,14 @@ class PostP extends React.Component<Props> {
|
||||
error={comments.error}
|
||||
/>
|
||||
|
||||
<LikeList
|
||||
likes={likes.items}
|
||||
areLoading={likes.areLoading}
|
||||
error={likes.error}
|
||||
/>
|
||||
{
|
||||
isPowerUser &&
|
||||
<LikeList
|
||||
likes={likes.items}
|
||||
areLoading={likes.areLoading}
|
||||
error={likes.error}
|
||||
/>
|
||||
}
|
||||
|
||||
<ActionBox
|
||||
followed={followed}
|
||||
@@ -213,7 +219,8 @@ class PostP extends React.Component<Props> {
|
||||
<div className="postHeader">
|
||||
<LikeButton
|
||||
postId={post.id}
|
||||
likesCount={likes.items.length}
|
||||
likeCount={likes.items.length}
|
||||
showLikeCount={isPowerUser || tenantSetting.show_vote_count}
|
||||
liked={likes.items.find(like => like.email === currentUserEmail) ? 1 : 0}
|
||||
isLoggedIn={isLoggedIn}
|
||||
authenticityToken={authenticityToken}
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import IPostStatus from '../../interfaces/IPostStatus';
|
||||
import { getLabel } from '../../helpers/formUtils';
|
||||
|
||||
const NO_POST_STATUS_VALUE = 'none';
|
||||
|
||||
@@ -28,16 +29,16 @@ const PostStatusSelect = ({
|
||||
id="selectPickerStatus"
|
||||
className="selectPicker"
|
||||
>
|
||||
<optgroup label="Post statuses">
|
||||
<optgroup label={getLabel('post_status')}>
|
||||
{postStatuses.map((postStatus, i) => (
|
||||
<option value={postStatus.id} key={i}>
|
||||
{postStatus.name}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
<optgroup label="No post status">
|
||||
<option value={NO_POST_STATUS_VALUE}>{I18n.t('post.post_status_select.no_post_status')}</option>
|
||||
</optgroup>
|
||||
<option value={NO_POST_STATUS_VALUE}>
|
||||
{I18n.t('post.post_status_select.no_post_status')}
|
||||
</option>
|
||||
</select>
|
||||
);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import IPostStatus from '../../interfaces/IPostStatus';
|
||||
|
||||
import { Store } from 'redux';
|
||||
import { State } from '../../reducers/rootReducer';
|
||||
import ITenantSetting from '../../interfaces/ITenantSetting';
|
||||
|
||||
interface Props {
|
||||
postId: number;
|
||||
@@ -19,6 +20,7 @@ interface Props {
|
||||
isPowerUser: boolean;
|
||||
currentUserFullName: string;
|
||||
currentUserEmail: string;
|
||||
tenantSetting: ITenantSetting;
|
||||
authenticityToken: string;
|
||||
}
|
||||
|
||||
@@ -40,6 +42,7 @@ class PostRoot extends React.Component<Props> {
|
||||
isPowerUser,
|
||||
currentUserFullName,
|
||||
currentUserEmail,
|
||||
tenantSetting,
|
||||
authenticityToken
|
||||
} = this.props;
|
||||
|
||||
@@ -54,6 +57,7 @@ class PostRoot extends React.Component<Props> {
|
||||
isPowerUser={isPowerUser}
|
||||
currentUserFullName={currentUserFullName}
|
||||
currentUserEmail={currentUserEmail}
|
||||
tenantSetting={tenantSetting}
|
||||
authenticityToken={authenticityToken}
|
||||
/>
|
||||
</Provider>
|
||||
|
||||
@@ -12,18 +12,23 @@ import {
|
||||
TENANT_SETTING_BRAND_DISPLAY_LOGO_ONLY,
|
||||
TENANT_SETTING_BRAND_DISPLAY_NONE,
|
||||
} from '../../../interfaces/ITenantSetting';
|
||||
import { DangerText } from '../../common/CustomTexts';
|
||||
import { DangerText, SmallMutedText } from '../../common/CustomTexts';
|
||||
import { getLabel, getValidationMessage } from '../../../helpers/formUtils';
|
||||
import IBoardJSON from '../../../interfaces/json/IBoard';
|
||||
|
||||
export interface ISiteSettingsGeneralForm {
|
||||
siteName: string;
|
||||
siteLogo: string;
|
||||
brandDisplaySetting: string;
|
||||
locale: string;
|
||||
showVoteCount: boolean;
|
||||
showVoteButtonInBoard: boolean;
|
||||
rootBoardId?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
originForm: ISiteSettingsGeneralForm;
|
||||
boards: IBoardJSON[];
|
||||
authenticityToken: string;
|
||||
|
||||
areUpdating: boolean;
|
||||
@@ -34,12 +39,16 @@ interface Props {
|
||||
siteLogo: string,
|
||||
brandDisplaySetting: string,
|
||||
locale: string,
|
||||
rootBoardId: number,
|
||||
showVoteCount: boolean,
|
||||
showVoteButtonInBoard: boolean,
|
||||
authenticityToken: string
|
||||
): Promise<any>;
|
||||
}
|
||||
|
||||
const GeneralSiteSettingsP = ({
|
||||
originForm,
|
||||
boards,
|
||||
authenticityToken,
|
||||
|
||||
areUpdating,
|
||||
@@ -56,6 +65,9 @@ const GeneralSiteSettingsP = ({
|
||||
siteLogo: originForm.siteLogo,
|
||||
brandDisplaySetting: originForm.brandDisplaySetting,
|
||||
locale: originForm.locale,
|
||||
showVoteCount: originForm.showVoteCount,
|
||||
showVoteButtonInBoard: originForm.showVoteButtonInBoard,
|
||||
rootBoardId: originForm.rootBoardId,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -65,6 +77,9 @@ const GeneralSiteSettingsP = ({
|
||||
data.siteLogo,
|
||||
data.brandDisplaySetting,
|
||||
data.locale,
|
||||
Number(data.rootBoardId),
|
||||
data.showVoteCount,
|
||||
data.showVoteButtonInBoard,
|
||||
authenticityToken,
|
||||
).then(res => {
|
||||
if (res?.status !== HttpStatus.OK) return;
|
||||
@@ -99,7 +114,7 @@ const GeneralSiteSettingsP = ({
|
||||
</div>
|
||||
|
||||
<div className="formGroup col-4">
|
||||
<label htmlFor="brandSetting">{ getLabel('tenant', 'brand_setting') }</label>
|
||||
<label htmlFor="brandSetting">{ getLabel('tenant_setting', 'brand_display') }</label>
|
||||
<select
|
||||
{...register('brandDisplaySetting')}
|
||||
id="brandSetting"
|
||||
@@ -136,6 +151,48 @@ const GeneralSiteSettingsP = ({
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="formGroup">
|
||||
<label htmlFor="rootBoardId">{ getLabel('tenant_setting', 'root_board_id') }</label>
|
||||
<select
|
||||
{...register('rootBoardId')}
|
||||
id="rootBoardId"
|
||||
className="selectPicker"
|
||||
>
|
||||
<option value="0">
|
||||
{I18n.t('roadmap.title')}
|
||||
</option>
|
||||
<optgroup label={getLabel('board')}>
|
||||
{boards.map((board, i) => (
|
||||
<option value={board.id} key={i}>{board.name}</option>
|
||||
))}
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div className="formGroup">
|
||||
<div className="checkboxSwitch">
|
||||
<input {...register('showVoteCount')} type="checkbox" id="show_vote_count_checkbox" />
|
||||
<label htmlFor="show_vote_count_checkbox">{ getLabel('tenant_setting', 'show_vote_count') }</label>
|
||||
<SmallMutedText>
|
||||
{ I18n.t('site_settings.general.show_vote_count_help') }
|
||||
</SmallMutedText>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div className="formGroup">
|
||||
<div className="checkboxSwitch">
|
||||
<input {...register('showVoteButtonInBoard')} type="checkbox" id="show_vote_button_in_board_checkbox" />
|
||||
<label htmlFor="show_vote_button_in_board_checkbox">{ getLabel('tenant_setting', 'show_vote_button_in_board') }</label>
|
||||
<SmallMutedText>
|
||||
{ I18n.t('site_settings.general.show_vote_button_in_board_help') }
|
||||
</SmallMutedText>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<Button onClick={() => null} disabled={!isDirty}>
|
||||
|
||||
@@ -4,11 +4,13 @@ import { Store } from 'redux';
|
||||
|
||||
import GeneralSiteSettings from '../../../containers/GeneralSiteSettings';
|
||||
import createStoreHelper from '../../../helpers/createStore';
|
||||
import IBoardJSON from '../../../interfaces/json/IBoard';
|
||||
import { State } from '../../../reducers/rootReducer';
|
||||
import { ISiteSettingsGeneralForm } from './GeneralSiteSettingsP';
|
||||
|
||||
interface Props {
|
||||
originForm: ISiteSettingsGeneralForm;
|
||||
boards: IBoardJSON[];
|
||||
authenticityToken: string;
|
||||
}
|
||||
|
||||
@@ -26,6 +28,7 @@ class GeneralSiteSettingsRoot extends React.Component<Props> {
|
||||
<Provider store={this.store}>
|
||||
<GeneralSiteSettings
|
||||
originForm={this.props.originForm}
|
||||
boards={this.props.boards}
|
||||
authenticityToken={this.props.authenticityToken}
|
||||
/>
|
||||
</Provider>
|
||||
|
||||
@@ -4,6 +4,7 @@ import I18n from 'i18n-js';
|
||||
|
||||
import Button from '../../common/Button';
|
||||
import IUser, { UserRoles, USER_ROLE_ADMIN, USER_ROLE_MODERATOR, USER_ROLE_USER } from '../../../interfaces/IUser';
|
||||
import { getLabel } from '../../../helpers/formUtils';
|
||||
|
||||
interface Props {
|
||||
user: IUser;
|
||||
@@ -57,7 +58,7 @@ class UserForm extends React.Component<Props, State> {
|
||||
id="selectPickerUserRole"
|
||||
className="selectPicker"
|
||||
>
|
||||
<optgroup label="Roles">
|
||||
<optgroup label={getLabel('user', 'role')}>
|
||||
<option value={USER_ROLE_USER}>
|
||||
{ I18n.t(`site_settings.users.role_${USER_ROLE_USER}`) }
|
||||
</option>
|
||||
|
||||
Reference in New Issue
Block a user