mirror of
https://github.com/wassname/talk.git
synced 2026-07-04 00:51:11 +08:00
Merge branch 'master' into i18n-refactor
This commit is contained in:
@@ -15,6 +15,6 @@ module.exports = (router) => {
|
||||
router.get('/api/v1/auth/facebook/callback', (req, res, next) => {
|
||||
|
||||
// Perform the facebook login flow and pass the data back through the opener.
|
||||
passport.authenticate('facebook', HandleAuthPopupCallback(req, res, next))(req, res, next);
|
||||
passport.authenticate('facebook', {session: false}, HandleAuthPopupCallback(req, res, next))(req, res, next);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015"
|
||||
],
|
||||
"plugins": [
|
||||
"add-module-exports",
|
||||
"transform-class-properties",
|
||||
"transform-decorators-legacy",
|
||||
"transform-object-assign",
|
||||
"transform-object-rest-spread",
|
||||
"transform-async-to-generator",
|
||||
"transform-react-jsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"rules": {
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error",
|
||||
"no-console": ["warn", { "allow": ["warn", "error"] }]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import {Icon} from 'coral-ui';
|
||||
import styles from './styles.css';
|
||||
import {I18n} from 'coral-framework';
|
||||
import translations from './translations.json';
|
||||
import {withReaction} from 'coral-plugin-api';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
class LoveButton extends React.Component {
|
||||
handleClick = () => {
|
||||
const {
|
||||
postReaction,
|
||||
deleteReaction,
|
||||
showSignInDialog,
|
||||
alreadyReacted
|
||||
} = this.props;
|
||||
const {root: {me}, comment} = this.props;
|
||||
|
||||
// If the current user does not exist, trigger sign in dialog.
|
||||
if (!me) {
|
||||
showSignInDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the current user is banned, do nothing.
|
||||
if (me.status === 'BANNED') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (alreadyReacted()) {
|
||||
deleteReaction();
|
||||
} else {
|
||||
postReaction();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {count, alreadyReacted} = this.props;
|
||||
return (
|
||||
<button
|
||||
className={`${styles.button} ${alreadyReacted() ? styles.loved : ''}`}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<span>{lang.t(alreadyReacted() ? 'loved' : 'love')}</span>
|
||||
<Icon name="favorite" />
|
||||
<span>{count > 0 && count}</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withReaction('love')(LoveButton);
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import styles from './style.css';
|
||||
import cn from 'classnames';
|
||||
|
||||
export default class LoveIcon extends React.Component {
|
||||
|
||||
render() {
|
||||
const {me} = this.props.data;
|
||||
let love = me && me.roles && me.roles[0] === 'ADMIN';
|
||||
|
||||
return (
|
||||
<div className={styles.love}>
|
||||
<button
|
||||
className={cn(styles.button, {[styles.love]: love})} >
|
||||
<i className={cn('love')} aria-hidden="true"/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
.love {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: #2a2a2a;
|
||||
margin: 5px 10px 5px 0px;
|
||||
background: none;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
font-size: inherit;
|
||||
|
||||
&:hover {
|
||||
color: #767676;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.love {
|
||||
color: #c98211;
|
||||
|
||||
&:hover {
|
||||
color: #e59614;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 0 5px;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import {compose, gql, graphql} from 'react-apollo';
|
||||
import LoveIcon from '../components/LoveIcon';
|
||||
|
||||
export const LOVE_QUERY = gql`
|
||||
query LoveQuery {
|
||||
me {
|
||||
status
|
||||
roles
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const withQuery = graphql(LOVE_QUERY);
|
||||
|
||||
const enhance = compose(
|
||||
withQuery,
|
||||
);
|
||||
|
||||
export default enhance(LoveIcon);
|
||||
@@ -0,0 +1,7 @@
|
||||
import LoveButton from './LoveButton';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
commentReactions: [LoveButton]
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
.respect {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: #2a2a2a;
|
||||
margin: 5px 10px 5px 0px;
|
||||
background: none;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
font-size: inherit;
|
||||
|
||||
&:hover {
|
||||
color: #767676;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.loved {
|
||||
color: #e52338;
|
||||
|
||||
&:hover {
|
||||
color: #e52839;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"en": {
|
||||
"love": "Love",
|
||||
"loved": "Loved"
|
||||
},
|
||||
"es": {
|
||||
"love": "Amo",
|
||||
"loved": "Amé"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
const {readFileSync} = require('fs');
|
||||
const path = require('path');
|
||||
const wrapResponse = require('../../graph/helpers/response');
|
||||
|
||||
module.exports = {
|
||||
typeDefs: readFileSync(path.join(__dirname, 'server/typeDefs.graphql'), 'utf8'),
|
||||
resolvers: {
|
||||
RootMutation: {
|
||||
createLove(_, {love: {item_id, item_type}}, {mutators: {Action}}) {
|
||||
return wrapResponse('love')(Action.create({item_id, item_type, action_type: 'LOVE'}));
|
||||
}
|
||||
}
|
||||
},
|
||||
hooks: {
|
||||
Action: {
|
||||
__resolveType: {
|
||||
post({action_type}) {
|
||||
switch (action_type) {
|
||||
case 'LOVE':
|
||||
return 'LoveAction';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ActionSummary: {
|
||||
__resolveType: {
|
||||
post({action_type}) {
|
||||
switch (action_type) {
|
||||
case 'LOVE':
|
||||
return 'LoveActionSummary';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
enum ACTION_TYPE {
|
||||
|
||||
# Represents a Love.
|
||||
LOVE
|
||||
}
|
||||
|
||||
enum ASSET_METRICS_SORT {
|
||||
|
||||
# Represents a LoveAction.
|
||||
LOVE
|
||||
}
|
||||
|
||||
input CreateLoveInput {
|
||||
|
||||
# The item's id for which we are to create a love.
|
||||
item_id: ID!
|
||||
|
||||
# The type of the item for which we are to create the love.
|
||||
item_type: ACTION_ITEM_TYPE!
|
||||
}
|
||||
|
||||
# LoveAction is used by users who "love" a specific entity.
|
||||
type LoveAction implements Action {
|
||||
|
||||
# The ID of the action.
|
||||
id: ID!
|
||||
|
||||
# The author of the action.
|
||||
user: User
|
||||
|
||||
# The time when the Action was updated.
|
||||
updated_at: Date
|
||||
|
||||
# The time when the Action was created.
|
||||
created_at: Date
|
||||
}
|
||||
|
||||
type LoveActionSummary implements ActionSummary {
|
||||
|
||||
# The count of actions with this group.
|
||||
count: Int
|
||||
|
||||
# The current user's action.
|
||||
current_user: LoveAction
|
||||
}
|
||||
|
||||
# A summary of counts related to all the Loves on an Asset.
|
||||
type LoveAssetActionSummary implements AssetActionSummary {
|
||||
|
||||
# Number of loves associated with actionable types on this this Asset.
|
||||
actionCount: Int
|
||||
|
||||
# Number of unique actionable types that are referenced by the loves.
|
||||
actionableItemCount: Int
|
||||
}
|
||||
|
||||
type CreateLoveResponse implements Response {
|
||||
|
||||
# The love that was created.
|
||||
love: LoveAction
|
||||
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
type RootMutation {
|
||||
|
||||
# Creates a love on an entity.
|
||||
createLove(love: CreateLoveInput!): CreateLoveResponse
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015"
|
||||
],
|
||||
"plugins": [
|
||||
"add-module-exports",
|
||||
"transform-class-properties",
|
||||
"transform-decorators-legacy",
|
||||
"transform-object-assign",
|
||||
"transform-object-rest-spread",
|
||||
"transform-async-to-generator",
|
||||
"transform-react-jsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"rules": {
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error",
|
||||
"no-console": ["warn", { "allow": ["warn", "error"] }]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.css'
|
||||
|
||||
export default (props) => (
|
||||
<div className={styles.box}>
|
||||
Comment Status: {props.comment.status}
|
||||
</div>
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import Box from './Box';
|
||||
import {Button} from 'coral-ui'
|
||||
import styles from './styles.css';
|
||||
|
||||
export default class Footer extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
show: false
|
||||
};
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.setState(state => ({
|
||||
show: !state.show
|
||||
}))
|
||||
}
|
||||
|
||||
render() {
|
||||
const {show} = this.state;
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Button cStyle="darkGrey" onClick={this.handleClick}>
|
||||
Show Comment Status
|
||||
</Button>
|
||||
{show ? <Box comment={this.props.comment} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
.container {
|
||||
padding: 0 14px 10px;
|
||||
}
|
||||
|
||||
.box {
|
||||
font-size: 12px;
|
||||
padding: 10px 14px;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Container from './components/Container';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
adminCommentDetailArea: [Container],
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
const {readFileSync} = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {};
|
||||
@@ -1,15 +1,15 @@
|
||||
import {compose, gql, graphql} from 'react-apollo';
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import get from 'lodash/get';
|
||||
import withFragments from 'coral-framework/hocs/withFragments';
|
||||
import {withFragments, withMutation} from 'coral-framework/hocs';
|
||||
import {showSignInDialog} from 'coral-framework/actions/auth';
|
||||
import RespectButton from '../components/RespectButton';
|
||||
|
||||
const isRespectAction = (a) => a.__typename === 'RespectActionSummary';
|
||||
|
||||
const COMMENT_FRAGMENT = gql`
|
||||
fragment RespectButton_updateFragment on Comment {
|
||||
fragment CoralRespect_UpdateFragment on Comment {
|
||||
action_summaries {
|
||||
... on RespectActionSummary {
|
||||
count
|
||||
@@ -21,8 +21,8 @@ const COMMENT_FRAGMENT = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
const withDeleteAction = graphql(gql`
|
||||
mutation deleteAction($id: ID!) {
|
||||
const withDeleteAction = withMutation(gql`
|
||||
mutation CoralRespect_DeleteAction($id: ID!) {
|
||||
deleteAction(id:$id) {
|
||||
errors {
|
||||
translation_key
|
||||
@@ -66,8 +66,8 @@ const withDeleteAction = graphql(gql`
|
||||
}),
|
||||
});
|
||||
|
||||
const withPostRespect = graphql(gql`
|
||||
mutation createRespect($respect: CreateRespectInput!) {
|
||||
const withPostRespect = withMutation(gql`
|
||||
mutation CoralRespect_CreateRespect($respect: CreateRespectInput!) {
|
||||
createRespect(respect: $respect) {
|
||||
respect {
|
||||
id
|
||||
@@ -131,20 +131,20 @@ const withPostRespect = graphql(gql`
|
||||
}),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
bindActionCreators({showSignInDialog}, dispatch);
|
||||
|
||||
const enhance = compose(
|
||||
withFragments({
|
||||
root: gql`
|
||||
fragment RespectButton_root on RootQuery {
|
||||
fragment CoralRespect_RespectButton_root on RootQuery {
|
||||
me {
|
||||
status
|
||||
}
|
||||
}
|
||||
`,
|
||||
comment: gql`
|
||||
fragment RespectButton_comment on Comment {
|
||||
fragment CoralRespect_RespectButton_comment on Comment {
|
||||
action_summaries {
|
||||
... on RespectActionSummary {
|
||||
count
|
||||
|
||||
Reference in New Issue
Block a user