Comments Support

This commit is contained in:
srgooglo 2020-03-24 02:45:46 +01:00
parent 46e443989d
commit 1c284e0070
15 changed files with 529 additions and 247 deletions

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
Endpoints: { Endpoints: {
comments_actions: "https://api.ragestudio.net/RSA-COMTY/r/comments?access_token=",
get_post_data: "https://api.ragestudio.net/RSA-COMTY/r/get-post-data?access_token=", get_post_data: "https://api.ragestudio.net/RSA-COMTY/r/get-post-data?access_token=",
get_user_tags: "https://api.ragestudio.net/RSA-COMTY/r/user_tags?access_token=", get_user_tags: "https://api.ragestudio.net/RSA-COMTY/r/user_tags?access_token=",
get_general_data: "https://api.ragestudio.net/RSA-COMTY/r/get-general-data?access_token=", get_general_data: "https://api.ragestudio.net/RSA-COMTY/r/get-general-data?access_token=",

View File

@ -3,7 +3,7 @@
"UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4", "UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4",
"title": "Comty™", "title": "Comty™",
"DevBuild": true, "DevBuild": true,
"version": "0.2.23", "version": "0.2.24",
"description": "", "description": "",
"main": "app/main.js", "main": "app/main.js",
"author": "RageStudio", "author": "RageStudio",
@ -20,7 +20,7 @@
"@lingui/react": "^2.9.1", "@lingui/react": "^2.9.1",
"@material-ui/core": "^4.9.3", "@material-ui/core": "^4.9.3",
"@material-ui/icons": "^4.9.1", "@material-ui/icons": "^4.9.1",
"antd": "^4.0.2", "antd": "^4.0.4",
"axios": "^0.19.2", "axios": "^0.19.2",
"babel-core": "7.0.0-bridge.0", "babel-core": "7.0.0-bridge.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -49,6 +49,7 @@
"react-sound": "^1.2.0", "react-sound": "^1.2.0",
"react-virtualized": "^9.21.2", "react-virtualized": "^9.21.2",
"store": "^2.0.12", "store": "^2.0.12",
"timeago.js": "^4.0.2",
"ts-cookies": "^1.0.0", "ts-cookies": "^1.0.0",
"umi-plugin-datahub": "^4.1.0", "umi-plugin-datahub": "^4.1.0",
"validator": "^12.2.0" "validator": "^12.2.0"

View File

@ -4,3 +4,5 @@ export * from './libs/yulio_id/pre.js';
export * from './libs/ycore_styles/pre.js'; export * from './libs/ycore_styles/pre.js';
export * from './libs/ycore_sdcp/pre.js'; export * from './libs/ycore_sdcp/pre.js';
export * from './libs/app_functions/pre.js' export * from './libs/app_functions/pre.js'

View File

@ -13,15 +13,11 @@ export const CheckThisApp = {
} }
return false return false
}, },
} }
export const SecondarySwap = { export const SecondarySwap = {
ext: ()=> { close: () => {
SwapMode.ext() SwapMode.close()
},
PostComments: (e) => {
SwapMode.PostComments(e)
}, },
openPost: (e) => { openPost: (e) => {
SwapMode.openPost(e) SwapMode.openPost(e)

View File

@ -34,7 +34,56 @@ export const IsThisPost = {
} }
} }
export const Post_Comments = {
delete: (callback, payload) => {
if (!payload) {
return false
}
const { comment_id } = payload
let formdata = new FormData();
formdata.append("type", "delete");
formdata.append("comment_id", comment_id);
API_Call((err,res)=> {
return callback(err,res)
},
ycore.endpoints.comments_actions,
formdata,
)
}
}
function API_Call(callback, endpoint, payload, options){
if (!payload || !endpoint) {
return false
}
let payloadContainer = payload;
payloadContainer.append("server_key", ycore.yConfig.server_key);
const defaultOptions = { method: "POST", timeout: 0, processData: false }
const { method, timeout, processData } = options || defaultOptions
const requestOptions = {
"url": `${endpoint}${ycore.handlerYIDT.__token()}`,
"method": method,
"timeout": timeout,
"data": payloadContainer,
"mimeType": "multipart/form-data",
"processData": processData,
"contentType": false
};
jquery.ajax(requestOptions)
.done(response => {
ycore.yconsole.log(response)
return callback(false, response)
})
.fail(error => {
ycore.yconsole.log('error', error)
ycore.Alive_API.fail(error)
return callback(true, error)
});
}
export function GetGeneralData(callback){ export function GetGeneralData(callback){
let formdata = new FormData(); let formdata = new FormData();
formdata.append("user_id", id); formdata.append("user_id", id);
@ -52,6 +101,7 @@ export function GetGeneralData(callback){
}) })
.catch(error => { .catch(error => {
console.log('error', error) console.log('error', error)
ycore.Alive_API.fail(error)
return callback(true, error) return callback(true, error)
}); });
} }
@ -73,6 +123,7 @@ export function follow_user(id, callback) {
return callback(false, response) return callback(false, response)
}) })
.catch(error => { .catch(error => {
ycore.Alive_API.fail(error)
console.log('error', error) console.log('error', error)
return callback(true, error) return callback(true, error)
}); });
@ -142,6 +193,7 @@ export function PublishPost(privacy, raw, file, callback){
}) })
.fail(error => { .fail(error => {
ycore.yconsole.log('error', error) ycore.yconsole.log('error', error)
ycore.Alive_API.fail(error)
return callback(true, error) return callback(true, error)
}); });
} }
@ -166,6 +218,7 @@ export function FindUser(key, callback){
}) })
.fail(function (response) { .fail(function (response) {
const exception = 'API Bad response'; const exception = 'API Bad response';
ycore.Alive_API.fail(response)
return callback(exception, response); return callback(exception, response);
}) })
} }
@ -190,29 +243,30 @@ export function SeachKeywords(key, callback){
}) })
.fail(function (response) { .fail(function (response) {
const exception = 'Request Failed'; const exception = 'Request Failed';
ycore.Alive_API.fail(response)
return callback(exception, response); return callback(exception, response);
}) })
} }
export function ActionPost(type, id, value, callback){ export function ActionPost(type, id, value, callback){
var formdata = new FormData();
formdata.append("server_key", ycore.yConfig.server_key);
if (!type || !id) { if (!type || !id) {
ycore.notifyError('[ActionPost] No type or id Provided !!!') ycore.notifyError('[ActionPost] No type or id Provided !!!')
return false return false
} }
var formdata = new FormData();
formdata.append("server_key", ycore.yConfig.server_key);
formdata.append("post_id", id);
switch (type) { switch (type) {
case 'like': case 'like':
{ {
formdata.append("action", "like"); formdata.append("action", "like");
formdata.append("post_id", id);
break break
} }
case 'commet': case 'comment':
{ {
if (!value) { if (!value) {
return false return false
} }
formdata.append("action", "commet"); formdata.append("action", "comment");
formdata.append("text", value) formdata.append("text", value)
break break
} }
@ -228,7 +282,6 @@ export function ActionPost(type, id, value, callback){
case 'delete': case 'delete':
{ {
formdata.append("action", "delete"); formdata.append("action", "delete");
formdata.append("post_id", id);
break break
} }
default: default:
@ -250,6 +303,7 @@ export function ActionPost(type, id, value, callback){
return callback(null, response); return callback(null, response);
}) })
.fail(function (response) { .fail(function (response) {
ycore.Alive_API.fail(response)
return callback(true, `[Server error] We couldnt ${type} this post`); return callback(true, `[Server error] We couldnt ${type} this post`);
}) })
} }
@ -277,6 +331,7 @@ export function GetUserTags(id, callback){
}) })
.fail(function (response) { .fail(function (response) {
const exception = 'Request Failed'; const exception = 'Request Failed';
ycore.Alive_API.fail(response)
return callback(exception, response); return callback(exception, response);
}) })
} }
@ -313,6 +368,7 @@ export function GetPosts(userid, type, fkey, callback) {
}) })
.fail(function (response) { .fail(function (response) {
const exception = 'Request Failed'; const exception = 'Request Failed';
ycore.Alive_API.fail(response)
return callback(exception, response); return callback(exception, response);
}) })
} }
@ -342,6 +398,7 @@ export function GetPostData(a, b, callback){
}) })
.fail(function (response) { .fail(function (response) {
const exception = 'Request Failed'; const exception = 'Request Failed';
ycore.Alive_API.fail(response)
return callback(exception, response); return callback(exception, response);
}) })
} }

View File

@ -11,6 +11,14 @@ var jwt = require("jsonwebtoken")
export function userData(){ export function userData(){
return ycore.handlerYIDT.get() return ycore.handlerYIDT.get()
} }
export const Alive_API = {
fail: (a) => {
if (a){
ycore.yconsole.log(a)
ycore.notify.error(a)
}
}
}
function __API__User (payload, sdcp, callback){ function __API__User (payload, sdcp, callback){
const { UserID, UserToken } = payload const { UserID, UserToken } = payload
@ -167,6 +175,9 @@ export function LogoutCall(){
ycore.handlerYIDT.remove() ycore.handlerYIDT.remove()
ycore.router.push({pathname: '/login',}) ycore.router.push({pathname: '/login',})
}) })
.fail((response) => {
ycore.Alive_API.fail(response)
})
} }
export function __AppSetup__(EncUsername, EncPassword, callback) { export function __AppSetup__(EncUsername, EncPassword, callback) {
const prefix = '[Auth Server]:'; const prefix = '[Auth Server]:';
@ -223,6 +234,7 @@ export function __AppSetup__(EncUsername, EncPassword, callback) {
}) })
.fail(function (response) { .fail(function (response) {
const exception = new Error("Server failed response . . . :( "); const exception = new Error("Server failed response . . . :( ");
ycore.Alive_API.fail(response)
return; return;
}) })
} }
@ -263,6 +275,7 @@ export function GetUserData (values, callback) {
.fail( .fail(
function (response) { function (response) {
ycore.yconsole.log(prefix, 'Server failure!', response) ycore.yconsole.log(prefix, 'Server failure!', response)
ycore.Alive_API.fail(response)
callback(true, response ) callback(true, response )
} }
) )

View File

@ -5,12 +5,13 @@
* @licensed Pending... * @licensed Pending...
*/ */
import {ListSettings} from "../../globals/settings.js";
import {Endpoints} from "globals/endpoints.js"; import {Endpoints} from "globals/endpoints.js";
import * as Icons from '@ant-design/icons'; import * as Icons from '@ant-design/icons';
import localforage from "localforage" import localforage from "localforage"
import { format } from 'timeago.js';
import umiRouter from "umi/router"; import umiRouter from "umi/router";
import * as antd from "antd"; import * as antd from "antd";
import moment from 'moment'
import React from "react"; import React from "react";
import config from "config" import config from "config"
@ -65,6 +66,22 @@ export function b64toBlob(b64Data, contentType, sliceSize) {
var blob = new Blob(byteArrays, {type: contentType}); var blob = new Blob(byteArrays, {type: contentType});
return blob; return blob;
} }
export const time = {
ago: (a) => {
const format = moment(a).format('DDMMYYYY');
const b = new Date(format).toLocaleString();
return time.relativeToNow(b);
},
stmToAgo: (a) => {
const b = (a*1000);
return format(b);
},
relativeToNow: (a, b) => {
return moment(a, b || "DDMMYYYY").fromNow();
}
}
export function objectLast(array, n) { export function objectLast(array, n) {
if (array == null) if (array == null)
return void 0; return void 0;

View File

@ -5,27 +5,17 @@ import * as Icons from '@ant-design/icons'
import styles from './index.less' import styles from './index.less'
import classnames from 'classnames' import classnames from 'classnames'
import SecRenderPost from './post' import {__priPost, __secComments} from './renders.js'
export const SwapMode = { export const SwapMode = {
ext: () => { close: () => {
SecondaryLayoutComponent.setState({ SecondaryLayoutComponent.closeSwap()
swap: true,
mode: 'ext'
})
}, },
PostComments: (e) => { openPost: (a, b) => {
SecondaryLayoutComponent.setState({ SecondaryLayoutComponent.setState({
swap: true, swap: true,
mode: 'post_comments', mode: 'post',
s_raw: e global_raw: a,
})
},
openPost: (e) => {
SecondaryLayoutComponent.setState({
swap: true,
mode: 'open_post',
s_raw: e
}) })
} }
} }
@ -36,48 +26,69 @@ export default class Secondary extends React.PureComponent{
window.SecondaryLayoutComponent = this; window.SecondaryLayoutComponent = this;
this.state = { this.state = {
swap: false, swap: false,
mode: 'ext', mode: '',
s_raw: '', global_raw: '',
pri_raw: '',
sec_raw: '',
} }
} }
closeSwap(){ closeSwap(){
this.setState({ this.setState({
swap: !this.state.swap, swap: !this.state.swap,
s_raw: null, pri_raw: null,
mode: 'ext' sec_raw: null,
mode: ''
}) })
} }
SwapBalanceContent(container){
switch (container){
case '__pri': {
return this.__pri()
}
case '__sec': {
return this.__sec()
}
default: return null
}
}
__pri(){
const dtraw = this.state.pri_raw;
switch (this.state.mode){
case 'post': {
return this.renderPost(this.state.global_raw)
}
default: return null
}
}
__sec(){
const dtraw = this.state.sec_raw;
switch (this.state.mode){
case 'post': {
return this.renderComments(this.state.global_raw)
}
default: return null
}
}
renderPost = (payload) => { renderPost = (payload) => {
const post_data = JSON.parse(payload)['post_data'] const post_data = JSON.parse(payload)['post_data']
console.log(post_data) console.log(post_data)
return( return(
<SecRenderPost payload={post_data} /> <__priPost payload={post_data} />
) )
} }
renderComments = (payload) => {
renderMode(){ const post_comments = JSON.parse(payload)['post_comments']
const { mode } = this.state const post_data = JSON.parse(payload)['post_data']
switch (mode) { console.log(post_comments)
case 'ext':
return (
<h1></h1>
)
case 'post_comments':{
return( return(
<PostComments s_raw={this.state.s_raw} /> <__secComments post_id={post_data.post_id} payload={post_comments} />
) )
} }
case 'open_post':{
return(
this.renderPost(this.state.s_raw)
)
}
default:
break;
}
}
render(){ render(){
@ -93,15 +104,12 @@ export default class Secondary extends React.PureComponent{
<div className={classnames(styles.container, {[styles.desktop_mode]: this.props.desktop_mode})} > <div className={classnames(styles.container, {[styles.desktop_mode]: this.props.desktop_mode})} >
<div className={styles.container_body}> <div className={styles.container_body}>
{this.state.swap? <antd.Button type="ghost" icon={<Icons.LeftOutlined />} onClick={() => this.closeSwap()} > Back </antd.Button> : null} {this.state.swap? <antd.Button type="ghost" icon={<Icons.LeftOutlined />} onClick={() => this.closeSwap()} > Back </antd.Button> : null}
{this.renderMode()} {this.SwapBalanceContent('__pri')}
</div> </div>
</div> </div>
<div className={classnames(styles.container_2, {[styles.active]: this.state.swap})}> <div className={classnames(styles.container_2, {[styles.active]: this.state.swap})}>
<h1>container_2</h1> {this.SwapBalanceContent('__sec')}
</div> </div>

View File

@ -4,6 +4,7 @@
width: 27%; width: 27%;
height: 100vh; height: 100vh;
position: relative; position: relative;
float: left; float: left;
overflow-y: hidden !important; overflow-y: hidden !important;
@ -12,7 +13,6 @@
display: flex; display: flex;
&.active{ &.active{
z-index: 10000;
width: 96vw; width: 96vw;
position: absolute; position: absolute;
right: 0; right: 0;
@ -31,7 +31,7 @@
top: 25px; top: 25px;
display: flex; display: flex;
position: absolute; position: absolute;
z-index: 202; z-index: 52;
img { img {
border-radius: 15px; border-radius: 15px;
width: 40px; width: 40px;
@ -53,7 +53,7 @@
} }
} }
.container{ .container{
z-index: 200; z-index: 50;
position: relative; position: relative;
background-color: #201F23; background-color: #201F23;
color: @DarkMode-color_container !important; color: @DarkMode-color_container !important;
@ -83,7 +83,7 @@
} }
.container_2{ .container_2{
z-index: 201; z-index: 51;
background-color: #fff; background-color: #fff;
border-radius: 32px 0 0 32px; border-radius: 32px 0 0 32px;
@ -104,3 +104,7 @@
transition: all @SwapAnimDuration ease-in-out; transition: all @SwapAnimDuration ease-in-out;
} }
.comments_body{
}

View File

@ -1,53 +0,0 @@
import React from 'react'
import styles from './post.less'
import * as antd from 'antd'
import * as ycore from 'ycore'
import Icon from '@ant-design/icons'
import {MediaPlayer, PostCard} from 'components'
const VerifiedBadge = () => (<svg xmlns="http://www.w3.org/2000/svg" fill="#55acee" width="15" height="15" viewBox="0 0 24 24"> <path d="M23 12l-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12 3 8.6 1.54 6.71 4.72l-3.61.81.34 3.68L1 12l2.44 2.78-.34 3.69 3.61.82 1.89 3.18L12 21l3.4 1.46 1.89-3.18 3.61-.82-.34-3.68L23 12m-13 5l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></svg>)
export default class SecRenderPost extends React.Component{
renderContent(payload){
const { id, postText, postFile_full, post_time, publisher} = payload
if (!postFile_full) {
return(
<div className={styles.postContent_OnlyText}>
<PostCard payload={payload} />
</div>
)
}
return (
<div className={styles.contentWrapper}>
{postFile_full? <MediaPlayer file={postFile_full} /> : null}
{postText? <div className={styles.postContent}> <h3 dangerouslySetInnerHTML={{__html: postText }} /> </div> : null}
</div>
)
}
render(){
const payload = this.props.payload
if (!payload) {
return (
<h1>This post not exists!!!</h1>
)
}
const { id, postText, postFile_full, post_time, publisher} = payload
return(
<div className={styles.SecondaryBody}>
<div className={styles.UserContainer}>
<div className={styles.UserContainer_text}>
<h4 className={styles.titleUser}>{publisher.username} {ycore.booleanFix(publisher.verified)? <Icon style={{ color: 'blue' }} component={VerifiedBadge} /> : null}</h4>
<p> {post_time} {ycore.IsThisUser.dev()? `| #${id}` : null} </p>
</div>
<antd.Avatar shape="square" size={50} src={publisher.avatar} />
</div>
{this.renderContent(payload)}
</div>
)
}
}

View File

@ -1,121 +0,0 @@
@import '~themes/vars.less';
.SecondaryBody{
width: 100%;
height: 100%;
}
.UserContainer{
display: flex;
position: relative;
float: right;
z-index: 150;
transform: translate(0, -40px);
.UserContainer_text{
margin: 0 8px;
h4 { text-align: right; }
p { word-break: break-all; text-align: right; font-size: 11px; color: #eeeeee!important; }
}
}
.postAvatar{
position: absolute;
left: -8px;
top: -8px;
display: flex;
}
.titleUser{
display: flex;
font-family: 'Poppins', sans-serif;
margin: 0 0 0 50px;
color: #ffffff!important;
}
.textAgo{
display: flex;
font-size: 10px;
margin: 0 0 0 53px;
}
.PostTags{
float: right;
width: 100%;
z-index: 10;
:global {
.anticon{
color:rgb(249, 179, 64);
float: right;
margin: -0 6px 0 0;;
font-size: 17px;
}
.MoreMenu{
color: #2d2d2d !important;
}
}
}
.titleWrapper{
display: flex;
h4{
cursor: pointer;
}
color: #ffffff!important;
}
.contentWrapper{
margin: auto;
width: 100%;
padding: 20px;
}
.postContent{
word-break: break-all;
position: absolute;
vertical-align: bottom;
border-radius: 7px;
bottom: 0;
max-width: 50vw;
background-color: #2d2d2d4b;
padding: 10px;
h3{
font-family: "Poppins", sans-serif;
color: #ffffff;
font-weight: 400;
font-size: 15px;
letter-spacing: -0.3px;
}
}
.postContent_OnlyText{
padding: 25% 0 0 0;
position: relative;
vertical-align: middle;
}
.likebtn{
:global{
svg{
color:rgba(0, 0, 0, 0.45);
}
svg:hover{
color: rgb(233, 35, 68);
transition: all 0.2s linear;
}
}
}
.ellipsisIcon{
color:rgba(0, 0, 0, 0.45);
width: 100%;
position: absolute;
text-align: center;
margin: auto;
font-size: 30px;
transition: opacity 150ms linear;
}
.ellipsisIcon:hover{
opacity: 0;
transition: opacity 150ms linear;
}

View File

@ -0,0 +1,152 @@
import React from 'react'
import styles from './renders.less'
import * as antd from 'antd'
import * as ycore from 'ycore'
import * as Icons from '@ant-design/icons'
import Icon from '@ant-design/icons'
import {MediaPlayer, PostCard} from 'components'
const VerifiedBadge = () => (<svg xmlns="http://www.w3.org/2000/svg" fill="#55acee" width="15" height="15" viewBox="0 0 24 24"> <path d="M23 12l-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12 3 8.6 1.54 6.71 4.72l-3.61.81.34 3.68L1 12l2.44 2.78-.34 3.69 3.61.82 1.89 3.18L12 21l3.4 1.46 1.89-3.18 3.61-.82-.34-3.68L23 12m-13 5l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></svg>)
export class __priPost extends React.Component{
renderContent(payload){
const { id, postText, postFile_full, post_time, publisher} = payload
if (!postFile_full) {
return(
<div className={styles.postContent_OnlyText}>
<PostCard payload={payload} />
</div>
)
}
return (
<div className={styles.contentWrapper}>
{postFile_full? <MediaPlayer file={postFile_full} /> : null}
{postText? <div className={styles.postContent}> <h3 dangerouslySetInnerHTML={{__html: postText }} /> </div> : null}
</div>
)
}
render(){
const payload = this.props.payload
if (!payload) {
return (
<h1>This post not exists!!!</h1>
)
}
const { id, postText, postFile_full, post_time, publisher} = payload
return(
<div className={styles.SecondaryBody}>
<div className={styles.UserContainer}>
<div className={styles.UserContainer_text}>
<h4 className={styles.titleUser}>{publisher.username} {ycore.booleanFix(publisher.verified)? <Icon style={{ color: 'blue' }} component={VerifiedBadge} /> : null}</h4>
<p> {post_time} {ycore.IsThisUser.dev()? `| #${id}` : null} </p>
</div>
<antd.Avatar shape="square" size={50} src={publisher.avatar} />
</div>
{this.renderContent(payload)}
</div>
)
}
}
export class __secComments extends React.Component {
state = {
comment_data: this.props.payload,
raw_comment: '',
loading: false
}
handleDeleteComment(id){
console.log(`Removing Comment with id => ${id}`)
ycore.Post_Comments.delete((err, res) => { if(err){return false} return this.reloadComments() }, {comment_id: id})
}
renderComment = (a) => {
const {id, time, Orginaltext, publisher} = a
const CommentMenu = (
<antd.Menu>
<antd.Menu.Item key="remove_comment" onClick={()=> this.handleDeleteComment(id)}><Icons.DeleteOutlined /> Delete</antd.Menu.Item>
</antd.Menu>
);
return (
<div className={styles.comment_card}>
<div className={styles.comment_title}>
<img src={publisher.avatar} />
<p className={styles.comment_user_username}>@{publisher.username} {ycore.booleanFix(publisher.verified)? <Icon style={{ color: 'black' }} component={VerifiedBadge} /> : null}</p>
<antd.Dropdown disabled={ycore.IsThisPost.owner(publisher.id)? false : true} overlay={CommentMenu} trigger={['click']}>
<p onClick={e => e.preventDefault()} className={styles.comment_user_ago}>{ycore.time.stmToAgo(time)}</p>
</antd.Dropdown>
</div>
<div className={styles.comment_text}>
<p>{Orginaltext}</p>
</div>
</div>
)
}
HandleCommentInput = e => {
const { value } = e.target;
this.setState({ raw_comment: value })
};
reloadComments(){
try {
this.setState({ loading: true })
ycore.GetPostData(this.props.post_id, null, (err, res) =>{
const post_comments = JSON.parse(res)['post_comments']
this.setState({ comment_data: post_comments, loading: false})
})
} catch (error) {
return false
}
}
dispatchNewComment(){
const { raw_comment } = this.state
const { post_id } = this.props
if (raw_comment) {
ycore.ActionPost('comment', post_id, raw_comment, (err,res) =>{
if (err) {
ycore.notify.error('This action could not be performed.', err)
}
this.setState({ raw_comment: '' })
this.reloadComments()
return true
})
}
return false
}
render(){
const {comment_data, loading} = this.state
return(
<div className={styles.comments_body}>
<div className={styles.comments_body_title}>
<h1>Comments ({comment_data.length})</h1>
</div>
<div className={styles.comments_cards_wrapper}>
{loading? <antd.Skeleton active/> :
<antd.List
itemLayout="horizontal"
dataSource={comment_data}
renderItem={item => (
this.renderComment(item)
)}
/>
}
</div>
<div className={styles.comment_box}>
<div className={styles.comment_box_body}>
<antd.Input value={this.state.raw_comment} onPressEnter={() => this.dispatchNewComment()} placeholder="Write a comment..." allowClear onChange={this.HandleCommentInput} />
</div>
</div>
</div>
)
}
}

View File

@ -0,0 +1,189 @@
@import '~themes/vars.less';
.SecondaryBody{
width: 100%;
height: 100%;
}
.UserContainer{
display: flex;
position: relative;
float: right;
z-index: 150;
transform: translate(0, -40px);
.UserContainer_text{
margin: 0 8px;
h4 { text-align: right; }
p { word-break: break-all; text-align: right; font-size: 11px; color: #eeeeee!important; }
}
}
.postAvatar{
position: absolute;
left: -8px;
top: -8px;
display: flex;
}
.titleUser{
display: flex;
font-family: 'Poppins', sans-serif;
margin: 0 0 0 50px;
color: #ffffff!important;
}
.textAgo{
display: flex;
font-size: 10px;
margin: 0 0 0 53px;
}
.PostTags{
float: right;
width: 100%;
z-index: 10;
:global {
.anticon{
color:rgb(249, 179, 64);
float: right;
margin: -0 6px 0 0;;
font-size: 17px;
}
.MoreMenu{
color: #2d2d2d !important;
}
}
}
.titleWrapper{
display: flex;
h4{
cursor: pointer;
}
color: #ffffff!important;
}
.contentWrapper{
margin: auto;
width: 100%;
padding: 20px;
}
.postContent{
word-break: break-all;
position: absolute;
vertical-align: bottom;
border-radius: 7px;
bottom: 0;
max-width: 50vw;
background-color: #2d2d2d4b;
padding: 10px;
h3{
font-family: "Poppins", sans-serif;
color: #ffffff;
font-weight: 400;
font-size: 15px;
letter-spacing: -0.3px;
}
}
.postContent_OnlyText{
padding: 25% 0 0 0;
position: relative;
vertical-align: middle;
}
.likebtn{
:global{
svg{
color:rgba(0, 0, 0, 0.45);
}
svg:hover{
color: rgb(233, 35, 68);
transition: all 0.2s linear;
}
}
}
.comments_body{
font-family: "Poppins", sans-serif;
padding: 75px 10px 10px 20px;
.comments_body_title{
font-size: 12px;
h1{
font-weight: 550;
letter-spacing: 0.01px;
}
}
.comments_cards_wrapper{
z-index: 50;
overflow: scroll;
:global{
overflow: scroll;
}
.comment_card{
position: relative;
width: 100%;
background-color: #ffffff;
word-break: break-all;
.comment_title{
display: flex;
img{
float: left;
width: 30px;
height: 30px;
border-radius: 12px;
}
.comment_user_username{
margin: 0 5px 0 8px;
vertical-align: middle;
height: 100%;
color: #2d2d2d;
line-height: 25px;
}
.comment_user_ago{
cursor: pointer;
position: absolute;
right: 0;
text-align: right;
font-size: 9px;
}
}
.comment_text{
margin: 10px 0 0 0;
}
}
}
.comment_box{
width: 100%;
bottom: 0;
right: 0;
position: absolute;
z-index: 100;
background-color: #ffffffd7;
padding-top: 20px;
padding-bottom: 40px;
border-radius: 0 0 0 32px;
.comment_box_body{
border-radius: 5px;
width: 85%;
height: 40px;
margin: auto;
background-color: #f8f6f8;
:global{
.ant-input-affix-wrapper, .ant-input{
padding: 4px 5px;
background-color: transparent;
border: 0;
}
}
}
}
}

View File

@ -62,6 +62,7 @@ class PostCard extends React.PureComponent{
goToPost(postID){ goToPost(postID){
localStorage.setItem('p_back_uid', postID) localStorage.setItem('p_back_uid', postID)
ycore.GetPostData(postID, null, (err, res) => { ycore.GetPostData(postID, null, (err, res) => {
console.log(res)
if (err) { return false } if (err) { return false }
ycore.SecondarySwap.openPost(res) ycore.SecondarySwap.openPost(res)
}) })
@ -70,7 +71,7 @@ class PostCard extends React.PureComponent{
render(){ render(){
const { payload, customActions } = this.props const { payload, customActions } = this.props
const ActShowMode = ycore.AppSettings.force_show_postactions const ActShowMode = ycore.AppSettings.force_show_postactions
const { id, post_time, postText, postFile, publisher, post_likes, is_post_pinned, is_liked } = payload || emptyPayload; const { id, post_time, postText, postFile, publisher, post_likes, is_post_pinned, is_liked, post_comments } = payload || emptyPayload;
const handlePostActions = { const handlePostActions = {
delete: (post_id) => { delete: (post_id) => {
ycore.ActionPost('delete', post_id, null, (err, res)=>{ ycore.ActionPost('delete', post_id, null, (err, res)=>{
@ -87,7 +88,7 @@ class PostCard extends React.PureComponent{
} }
const defaultActions = [ const defaultActions = [
<div><LikeBTN count={post_likes} id={id} liked={ycore.booleanFix(is_liked)? true : false} key="like" /></div>, <div><LikeBTN count={post_likes} id={id} liked={ycore.booleanFix(is_liked)? true : false} key="like" /></div>,
<MICON.InsertComment key="comments" onClick={ ()=> this.goToPost(id) } /> <antd.Badge dot={post_comments > 0 ? true : false}><MICON.InsertComment key="comments" onClick={ ()=> this.goToPost(id) } /></antd.Badge>
] ]
const actions = customActions || defaultActions; const actions = customActions || defaultActions;

View File

@ -28,7 +28,7 @@
transition: opacity 150ms linear, position 150ms linear, transform 150ms linear; transition: opacity 150ms linear, position 150ms linear, transform 150ms linear;
border-radius: 0 0 10px 10px; border-radius: 0 0 10px 10px;
opacity: 0; opacity: 0;
// Doesn't work... So sad :C
&.showMode{ &.showMode{
opacity: 1; opacity: 1;
transform: translate(0, 15px); transform: translate(0, 15px);
@ -40,7 +40,7 @@
transform: translate(0, 15px); transform: translate(0, 15px);
transition: opacity 150ms linear, position 150ms linear, transform 150ms linear; transition: opacity 150ms linear, position 150ms linear, transform 150ms linear;
} }
.ant-card-actions > li > span > .anticon { .ant-card-actions > li > .anticon {
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;
width: 40px; width: 40px;
@ -52,6 +52,21 @@
.ant-card-actions > li { .ant-card-actions > li {
margin: -20px 0 0 0 ; margin: -20px 0 0 0 ;
border-right: 0; border-right: 0;
.ant-badge-count{
width: 20px;
text-align: left;
span {
font-size: 12px;
}
.ant-scroll-number-only > p.ant-scroll-number-only-unit {
height: 20px;
width: 20px;
margin: 0;
line-height: 20px;
padding: 0 0 0 1px;
}
}
span { span {
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;