diff --git a/.babelrc b/.babelrc index 3dcf42eb7..92a64c2a4 100644 --- a/.babelrc +++ b/.babelrc @@ -10,5 +10,12 @@ "transform-async-to-generator", "transform-react-jsx", "syntax-dynamic-import" - ] + ], + "env": { + "test": { + "plugins": [ + ["transform-es2015-modules-commonjs", "dynamic-import-node"] + ] + } + } } diff --git a/.gitignore b/.gitignore index 9c55f2708..0ab845e4e 100644 --- a/.gitignore +++ b/.gitignore @@ -45,5 +45,6 @@ plugins/* !plugins/talk-plugin-deep-reply-count !plugins/talk-plugin-subscriber !plugins/talk-plugin-flag-details +!plugins/talk-plugin-slack-notifications **/node_modules/* diff --git a/README.md b/README.md index 919093750..057b29cf1 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ # Talk [![CircleCI](https://circleci.com/gh/coralproject/talk.svg?style=svg)](https://circleci.com/gh/coralproject/talk) + [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2Fcoralproject%2Ftalk&env[TALK_FACEBOOK_APP_ID]=ignore&env[TALK_FACEBOOK_APP_SECRET]=ignore) Online comments are broken. Our open-source Talk tool rethinks how moderation, comment display, and conversation function, creating the opportunity for safer, smarter discussions around your work. [Read more about Talk here](https://coralproject.net/products/talk.html). -## Documentation +Built with <3 by The Coral Project & Mozilla. -Developer Documentation & Setup Guides https://coralproject.github.io/talk/. +## Getting Started + +Check out our Docs: https://coralproject.github.io/talk/ ## Relevant Links diff --git a/client/coral-admin/src/components/ui/Header.css b/client/coral-admin/src/components/ui/Header.css index f85a7cdf9..1bb08b8a2 100644 --- a/client/coral-admin/src/components/ui/Header.css +++ b/client/coral-admin/src/components/ui/Header.css @@ -16,19 +16,18 @@ } .header { - background-color: transparent; box-shadow: none; min-height: 58px; display: block; + background-color: #696969; + box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); } .header > div { - background-color: #696969; position: relative; padding: 0; - min-width: 1280px; + width: 1280px; margin: 0 auto; - box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); height: 58px; } diff --git a/client/coral-admin/src/components/ui/Layout.css b/client/coral-admin/src/components/ui/Layout.css index a3cc7b7b6..924c6ced7 100644 --- a/client/coral-admin/src/components/ui/Layout.css +++ b/client/coral-admin/src/components/ui/Layout.css @@ -1,5 +1,4 @@ .layout { - max-width: 1280px; margin: 0 auto; background-color: #FAFAFA; } diff --git a/client/coral-admin/src/routes/Community/components/FlaggedAccounts.css b/client/coral-admin/src/routes/Community/components/FlaggedAccounts.css index 4e9600cbd..a41bda485 100644 --- a/client/coral-admin/src/routes/Community/components/FlaggedAccounts.css +++ b/client/coral-admin/src/routes/Community/components/FlaggedAccounts.css @@ -2,6 +2,8 @@ padding: 10px; display: flex; padding-bottom: 200px; + max-width: 1280px; + margin: 0 auto; } .mainFlaggedContent { diff --git a/client/coral-admin/src/routes/Configure/components/Configure.css b/client/coral-admin/src/routes/Configure/components/Configure.css index 0b7319132..eae75caba 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.css +++ b/client/coral-admin/src/routes/Configure/components/Configure.css @@ -3,6 +3,8 @@ */ .container { + max-width: 1280px; + margin: 0 auto; display: flex; h3 { diff --git a/client/coral-admin/src/routes/Dashboard/components/Dashboard.css b/client/coral-admin/src/routes/Dashboard/components/Dashboard.css index 586ff6c08..aee7e702b 100644 --- a/client/coral-admin/src/routes/Dashboard/components/Dashboard.css +++ b/client/coral-admin/src/routes/Dashboard/components/Dashboard.css @@ -4,6 +4,8 @@ .Dashboard { display: flex; + max-width: 1280px; + margin: 0 auto; } .heading { diff --git a/client/coral-admin/src/routes/Stories/components/Stories.css b/client/coral-admin/src/routes/Stories/components/Stories.css index d8a75a4ce..be6b6f921 100644 --- a/client/coral-admin/src/routes/Stories/components/Stories.css +++ b/client/coral-admin/src/routes/Stories/components/Stories.css @@ -1,6 +1,8 @@ .container { padding: 10px; display: flex; + max-width: 1280px; + margin: 0 auto; } .leftColumn { diff --git a/client/coral-embed-stream/src/components/CountdownSeconds.js b/client/coral-embed-stream/src/components/CountdownSeconds.js index 789b674b5..46b6b1fbf 100644 --- a/client/coral-embed-stream/src/components/CountdownSeconds.js +++ b/client/coral-embed-stream/src/components/CountdownSeconds.js @@ -35,16 +35,23 @@ export class CountdownSeconds extends React.Component { const {until, classNameForMsRemaining} = this.props; const msRemaining = until - now; const secRemaining = msRemaining / 1000; - const wholeSecRemaining = Math.floor(secRemaining); - const plural = secRemaining !== 1; - const units = t(plural ? 'edit_comment.seconds_plural' : 'edit_comment.second'); + const minRemaining = secRemaining / 60; + const secToMinRemaining = secRemaining % 60; + const wholeMinRemaining = Math.floor(minRemaining); + const wholeSecRemaining = Math.floor(secToMinRemaining); + const secUnit = t(wholeSecRemaining !== 1 ? 'edit_comment.seconds_plural' : 'edit_comment.second'); + const minUnit = t(wholeMinRemaining !== 1 ? 'edit_comment.minutes_plural' : 'edit_comment.minute'); let classFromProp; if (typeof classNameForMsRemaining === 'function') { classFromProp = classNameForMsRemaining(msRemaining); } + const text = wholeMinRemaining > 0 + ? `${wholeMinRemaining} ${minUnit} ${wholeSecRemaining} ${secUnit}` + : `${wholeSecRemaining} ${secUnit}`; + return ( - {`${wholeSecRemaining} ${units}`} + {text} ); } diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index a20c94d1a..0dcbf856e 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -270,6 +270,7 @@ button.comment__action-button[disabled], width: 75%; font-size: 16px; border: 1px solid #ccc; + max-width: calc(100% - 40px); } /* Close comments */ diff --git a/client/talk-plugin-infobox/__tests__/markdown.spec.js b/client/coral-framework/components/__tests__/Markdown.spec.js similarity index 81% rename from client/talk-plugin-infobox/__tests__/markdown.spec.js rename to client/coral-framework/components/__tests__/Markdown.spec.js index 1d98dabae..ab2c1afd1 100644 --- a/client/talk-plugin-infobox/__tests__/markdown.spec.js +++ b/client/coral-framework/components/__tests__/Markdown.spec.js @@ -1,6 +1,5 @@ import React from 'react'; import {shallow} from 'enzyme'; -import {expect} from 'chai'; import Markdown from '../Markdown'; const render = (props) => shallow(); @@ -9,12 +8,12 @@ describe('Markdown', () => { it('should convert Markdown to html', () => { const wrapper = render({content: '*test*'}); const html = wrapper.html(); - expect(html).to.contain(''); + expect(html).toMatch(''); }); it('should set target="_parent" for links', () => { const wrapper = render({content: '[link](https://coralproject.net)'}); const html = wrapper.html(); - expect(html).to.contain('target="_parent"'); + expect(html).toMatch('target="_parent"'); }); }); diff --git a/client/coral-framework/services/i18n.js b/client/coral-framework/services/i18n.js index 1a4910b21..87e375853 100644 --- a/client/coral-framework/services/i18n.js +++ b/client/coral-framework/services/i18n.js @@ -13,7 +13,7 @@ import pt_BR from '../../../locales/pt_BR.yml'; // Translations are happening at https://translate.lingohub.com/the-coral-project/dashboard -const defaultLanguage = 'en'; +const defaultLanguage = process.env.TALK_DEFAULT_LANG; const translations = {...en, ...es, ...fr, ...pt_BR}; let lang; diff --git a/client/talk-plugin-commentbox/CommentForm.js b/client/talk-plugin-commentbox/CommentForm.js index f4bbbd139..55d248994 100644 --- a/client/talk-plugin-commentbox/CommentForm.js +++ b/client/talk-plugin-commentbox/CommentForm.js @@ -85,8 +85,8 @@ export class CommentForm extends React.Component { render() { const {maxCharCount, submitEnabled, cancelButtonClassName, submitButtonClassName, charCountEnable, body, loadingState} = this.props; - const length = body.length; - const isRespectingMaxCount = (length) => charCountEnable && maxCharCount && length > maxCharCount; + const length = body.trim().length; + const isRespectingMaxCount = (length) => charCountEnable && maxCharCount && length > maxCharCount; const disableSubmitButton = !length || isRespectingMaxCount(length) || !submitEnabled({body}) || loadingState === 'loading'; const disableCancelButton = loadingState === 'loading'; const disableTextArea = loadingState === 'loading'; diff --git a/client/talk-plugin-commentbox/__tests__/commentBox.spec.js b/client/talk-plugin-commentbox/__tests__/commentBox.spec.js deleted file mode 100644 index 6ae09e786..000000000 --- a/client/talk-plugin-commentbox/__tests__/commentBox.spec.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import {shallow} from 'enzyme'; -import {expect} from 'chai'; -import CommentBox from '../CommentBox'; - -describe('CommentBox', () => { - let comment; - let render; - beforeEach(() => { - comment = {}; - const postItem = (item) => { - comment.posted = item; - return Promise.resolve(4); - }; - render = shallow( comment.text = e.target.value} - item_id={'1'} - comments={['1', '2', '3']}/>); - }); - - it('should render the CommentBox appropriately', () => { - expect(render.contains('
shallow(); describe('InfoBox', () => { + it('renders correctly', () => { + const tree = renderer.create( + + ).toJSON(); + expect(tree).toMatchSnapshot(); + }); + it('should render hidden InfoBox', () => { const wrapper = render(); const className = wrapper.prop('className'); - expect(className).to.include('-info'); - expect(className).to.include('hidden'); + expect(className).toMatch('-info'); + expect(className).toMatch('hidden'); }); it('should render enabled InfoBox', () => { const wrapper = render({enable: true}); const className = wrapper.prop('className'); - expect(className).to.include('-info'); - expect(className).to.not.include('hidden'); + expect(className).toMatch('-info'); + expect(className).not.toMatch('hidden'); }); it('should render Markdown', () => { const wrapper = render({content: 'x'}); const Markddown = wrapper.find('Markdown'); - expect(Markddown).to.have.length(1); - expect(Markddown.prop('content')).to.equal('x'); + expect(Markddown).toHaveLength(1); + expect(Markddown.prop('content')).toEqual('x'); }); }); diff --git a/client/talk-plugin-infobox/__tests__/__snapshots__/InfoBox.spec.js.snap b/client/talk-plugin-infobox/__tests__/__snapshots__/InfoBox.spec.js.snap new file mode 100644 index 000000000..4c90404bd --- /dev/null +++ b/client/talk-plugin-infobox/__tests__/__snapshots__/InfoBox.spec.js.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`InfoBox renders correctly 1`] = ` +
+
test

+", + } + } + /> +
+`; diff --git a/docs/_docs/running-advanced-configuration.md b/docs/_docs/running-advanced-configuration.md index 5512f60cb..7db27fb1c 100644 --- a/docs/_docs/running-advanced-configuration.md +++ b/docs/_docs/running-advanced-configuration.md @@ -24,6 +24,10 @@ otherwise the application will fail to start. Configure the duration for which comment counts are cached for, parsed by [ms](https://www.npmjs.com/package/ms){:target="_blank"}. (Default `1hr`) +## TALK_DEFAULT_LANG + +Specify the default translation language. (Default `en`) + ## TALK_DEFAULT_STREAM_TAB Specify the default stream tab in the admin. (Default `all`) @@ -439,4 +443,4 @@ Could be read as: again, then they must have two of their comments approved in order to get added back to the queue. - At the moment of writing, behavior is not attached to the flagging - reliability, but it is recorded. \ No newline at end of file + reliability, but it is recorded. diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..b070d8fc1 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,39 @@ +const path = require('path'); +const {pluginsPath} = require('./plugins'); + +const buildTargets = [ + 'coral-admin', + 'coral-docs' +]; + +const buildEmbeds = [ + 'stream' +]; + +// jest.config.js +module.exports = { + testMatch: ['**/client/**/__tests__/**/*.js?(x)'], + setupTestFrameworkScriptFile: '/test/client/setupJest.js', + modulePaths: [ + '/plugins', + '/client', + ...buildTargets.map((target) => path.join('', 'client', target, 'src')), + ...buildEmbeds.map((embed) => path.join('', 'client', `coral-embed-${embed}`, 'src')), + ], + moduleFileExtensions: ['js', 'jsx', 'json', 'yaml', 'yml'], + moduleDirectories: ['node_modules'], + + transform: { + '^.+\\.jsx?$': 'babel-jest', + '\\.ya?ml$': '/test/client/yamlTransformer.js' + }, + + moduleNameMapper: { + '^plugin-api\\/(.*)$': '/plugin-api/$1', + '^plugins\\/(.*)$': '/plugins/$1', + '^pluginsConfig$': pluginsPath, + + '\\.(scss|css|less)$': 'identity-obj-proxy', + '\\.(gif|ttf|eot|svg)$': '/test/client/fileMock.js' + } +}; diff --git a/locales/en.yml b/locales/en.yml index 1a934b695..92119f125 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -172,6 +172,8 @@ en: edit_window_timer_prefix: "Edit Window: " second: "second" seconds_plural: "seconds" + minute: "minute" + minutes_plural: "minutes" email: confirm: has_been_requested: "A email confirmation has been requested for the following account:" @@ -186,7 +188,7 @@ en: embedlink: copy: "Copy to Clipboard" error: - COMMENT_TOO_SHORT: "Your comment must have something in it" + COMMENT_TOO_SHORT: "Comments should be more than one character, please revise your comment and try again." NOT_AUTHORIZED: "You are not authorized to perform this action." NO_SPECIAL_CHARACTERS: "Usernames can contain letters numbers and _ only" PASSWORD_LENGTH: "Password is too short" diff --git a/locales/es.yml b/locales/es.yml index 8b257b72e..62fc94256 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -171,6 +171,8 @@ es: edit_window_timer_prefix: "Ventana Edición:" second: "segundo" seconds_plural: "segundos" + minute: "minuto" + minutes_plural: "minutos" email: confirm: has_been_requested: "Un correo de confirmación ha sido pedido para la siguiente cuenta:" diff --git a/locales/fr.yml b/locales/fr.yml index f8ff403e7..f703c87f1 100644 --- a/locales/fr.yml +++ b/locales/fr.yml @@ -140,6 +140,8 @@ fr: edit_window_timer_prefix: "Fenêtre d'édition :" second: "seconde" seconds_plural: "secondes" + minute: "minute" + minutes_plural: "minutes" unexpected_error: "Erreur inattendue lors de l'enregistrement des modifications. Désolé !" embedlink: copy: "Copier dans le presse-papier" diff --git a/locales/pt_BR.yml b/locales/pt_BR.yml index 3f2c92628..a23c1ad8c 100644 --- a/locales/pt_BR.yml +++ b/locales/pt_BR.yml @@ -1,122 +1,131 @@ pt_BR: your_account_has_been_suspended: Sua conta foi temporariamente suspensa. your_account_has_been_banned: Sua conta foi banida. - your_username_has_been_rejected: Sua conta foi suspensa porque seu nome de usuário foi considerado inapropriado. Para restaurar sua conta, insira um novo nome de usuário. + your_username_has_been_rejected: Sua conta foi rejeitada porque seu nome de usuário foi considerado inapropriado. Para restaurar sua conta, insira um novo nome de usuário. embed_comments_tab: Comentários bandialog: - are_you_sure: "Tem certeza de que gostaria de proibir a {0}?" - ban_user: "Proibir o usuário?" - banned_user: "Usuário proibido" + are_you_sure: "Tem certeza de que gostaria de banir {0}?" + ban_user: "Deseja banir o usuário?" + banned_user: "Usuário banido" cancel: "Cancelar" note: "Nota: {0}" - note_reject_comment: "Proibir esse usuário também colocará esse comentário na fila rejeitada." - note_ban_user: "Proibir este usuário não os permitirá editar comentários ou remover qualquer coisa." - yes_ban_user: "Sim, proiber o usuário" - bio_offensive: "Essa bio é ofensiva" + note_reject_comment: "Banir esse usuário também colocará esse comentário na fila rejeitada." + note_ban_user: "Banir este usuário não os permitirá editar comentários ou remover qualquer coisa." + yes_ban_user: "Sim, banir o usuário" + bio_offensive: "Esse perfil é ofensiva" cancel: "Cancelar" characters_remaining: "caracteres restantes" comment: anon: "Anônimo" - ban_user: "Proibir o usuário" - comment: "Publicar um comentário" + ban_user: "Banir o usuário" + comment: "Escreva um comentário..." edited: Editado - flagged: "marcado" + flagged: "Marcado" view_context: "Veja o contexto" comment_box: - post: "Publicar" + post: "Enviar" cancel: "Cancelar" reply: "Responder" - comment: "Publicar um comentário" + comment: "Escreva um comentário..." name: "Nome" - comment_post_notif: "Seu comentário foi postado." - comment_post_notif_premod: "Obrigado por publicar seu comentário. Nossa equipe de moderação analisará seu comentário em breve." - comment_post_banned_word: "O seu comentário contém uma ou mais palavras que não são permitidas, portanto, não serão publicadas. Se você acha que esta mensagem está incorreta, contate nossa equipe de moderação." + comment_post_notif: "Seu comentário foi enviado." + comment_post_notif_premod: "Obrigado por compartilhar sua opinião. Nossa equipe de moderação analisará seu comentário em breve." + comment_post_banned_word: "Seu comentário não foi publicado porque contém conteúdo inadequado." characters_remaining: "caracteres restantes" comment_offensive: "Este comentário é ofensivo" comment_singular: Comentário comment_plural: Comentários - comment_post_banned_word: "O seu comentário contém uma ou mais palavras que não são permitidas, portanto, não serão publicadas. Se você acha que esta mensagem está incorret a, contate nossa equipe de moderação." + comment_post_banned_word: "Seu comentário não foi publicado porque contém conteúdo inadequado." comment_post_notif: "Seu comentário foi postado." - comment_post_notif_premod: "Obrigado por publicar seu comentário. Nossa equipe de moderação analisará seu comentário em breve." + comment_post_notif_premod: "Obrigado por compartilhar sua opinião. Nossa equipe de moderação analisará seu comentário em breve." common: - copy: 'Copie' + copy: 'Copiar' error: 'Ocorreu um erro.' + reply: 'Resposta' + replies: 'Respostas' + reaction: 'Reação' + reactions: 'Reações' + story: 'Conversas' community: account_creation_date: "Data de criação da conta" active: Ativo admin: Administrador - ads_marketing: "Isso parece anúncio/marketing" - are_you_sure: "Você tem certeza de que gostaria de proibir a {0}?" - ban_user: "Proibir o usuário?" - banned: Proibida - banned_user: "Usuário proibido" + ads_marketing: "Este comentário parece anúncio" + are_you_sure: "Você tem certeza de que gostaria de banir {0}?" + ban_user: "Banir o usuário?" + banned: Banido + banned_user: "Usuário banido" cancel: Cancelar - flaggedaccounts: "Nomes de usuários marcados" + dont_like_username: "Descurtir usuário" + flaggedaccounts: "Usuários marcados" flags: Marcadas impersonating: "Representação" loading: "Carregando resultados" moderator: Moderador - newsroom_role: "Papel de empresa" - no_flagged_accounts: "A fila de nomes de usuários marcados está atualmente vazia." + newsroom_role: "Papel da empresa" + no_flagged_accounts: "A fila de usuários marcados está atualmente vazia." no_results: "Nenhum usuário encontrado com esse nome de usuário ou e-mail. Eles estão se escondendo!" + offensive: "Ofensivo" + other: Outros people: Pessoas role: "Selecione um papel..." select_status: "Selecione um status..." - staff: "Funcionários" - status: Status + spam_ads: "Spam/Ads" + staff: "Equipe" + status: Situação username_and_email: "Nome de usuário e email" - yes_ban_user: "Sim, proibir esse usuário" + yes_ban_user: "Sim, banir este usuário" configure: apply: Aplicar - banned_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão automaticamente removidos do hilo de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar. Opcionalmente cole uma lista separada por vírgulas." + banned_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão automaticamente removidos da lista de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar ou cole uma lista separada por vírgulas." banned_words_title: "Lista de palavras proibidas" close: "Fechar" - close_after: "Feche os comentários após" - close_stream: "Feche hilo de comentários" - close_stream_configuration: "Esse hilo de comentários está fechado no momento. Ao abrir esse hilo de comentários, novos comentários podem ser enviados e exibidos." - closed_comments_desc: "Escreva uma mensagem a ser exibida quando o seu hilo de comentários for fechado e deixando de aceitar comentários." - closed_comments_label: "Escreve uma mensagem..." + close_after: "Fechar comentários após" + close_stream: "Fechar comentários" + close_stream_configuration: "Comentários fechados no momento. Ao abrir comentários, novos comentários podem ser enviados e exibidos." + closed_comments_desc: "Escreva uma mensagem a ser exibida quando os comentários estiverem fechados." + closed_comments_label: "Escreva uma mensagem..." closed_stream_settings: "Mensagem de comentários fechados" comment_count_error: "Por favor insira um número válido." - comment_count_header: "Limite o comprimento do comentário" + comment_count_header: "Limite o tamanho do comentário" comment_count_text_post: caracteres comment_count_text_pre: "Os comentários serão limitados a" comment_settings: Configurações - comment_stream: "Hilo de comentários" - comment_stream_will_close: "O hilo de comentários será fechado" - community: Comunidade + comment_stream: "Lista de comentários" + comment_stream_will_close: "Comentários fechados" + community: Usuários configure: Configurar copy_and_paste: "Copie e cole o código abaixo em seu CMS para incorporar sua caixa de comentários em seus artigos." - custom_css_url: "URL personalizado do CSS" - custom_css_url_desc: "URL de uma folha de estilo CSS que irá substituir os estilos padrão dos comentários embutidos. Pode ser interno ou externo." + custom_css_url: "URL para CSS customizado" + custom_css_url_desc: "URL de uma folha de estilo CSS para substituir os estilos padrão dos comentários embutidos. Pode ser interno ou externo." dashboard: Painel de controle days: Dias - description: "Como administrador, você pode personalizar as configurações do hilo de comentários para esta história:" - domain_list_text: "Insira os domínios que você gostaria de permitir para o Talk, como o seu site de preparação ou site de produção (ej. localhost:3000 staging.domain.com domain.com)." + description: "Como administrador, você pode personalizar as configurações da lista de comentários para esta história:" + domain_list_text: "Insira os domínios que você gostaria de permitir para o Talk, como seus ambientes de desenvolvimento, teste ou produção (ej. localhost:3000 staging.domain.com domain.com)." domain_list_title: "Domínios permitidos" edit_comment_timeframe_heading: "Período de tempo para editar comentários" - edit_comment_timeframe_text_pre: "Os comentadores terão" + edit_comment_timeframe_text_pre: "Os usuários terão" edit_comment_timeframe_text_post: "segundos para editar seus comentários." embed_comment_stream: "Comentários embutidos" - enable_premod_links_text: "Os moderadores devem aprovar qualquer comentário contendo um link antes de ser publicado." + enable_premod_links_text: "Demandar aprovação de moderadores antes de publicar comentários com links." enable_pre_moderation: "Habilitar pré-moderação" - enable_pre_moderation_text: "Os moderadores devem aprovar qualquer comentário antes de ser publicado." + enable_pre_moderation_text: "Demandar aprovação de moderadores para todos os comentários." enable_premod_links: "Os moderadores devem aprovar qualquer comentário antes de ser publicado." enable_premod: "Habilitar pré-moderação" - enable_premod_description: "Moderators must approve any comment before it is published." - enable_premod_links_description: "Os moderadores devem aprovar qualquer comentário antes de ser publicado." + enable_premod_description: "Demandar aprovação de moderadores para todos os comentários." + enable_premod_links_description: "Demandar aprovação de moderadores antes de publicar comentários com links." enable_questionbox: "Faça uma pergunta aos leitores" - enable_questionbox_description: "Esta pergunta aparecerá no topo deste hilo de comentários. Pergunte aos leitores sobre um determinado problema no artigo ou coloca questões de discussão, etc." + enable_questionbox_description: "Esta pergunta aparecerá no topo da lista de comentários. Pergunte aos leitores sobre um determinado problema no artigo, abra o assunto para discussão, etc." hours: Horas - include_comment_stream: "Incluir descrição de hilo de comentários para leitores" + include_comment_stream: "Incluir descrição da lista comentários para leitores" include_comment_stream_desc: "Escreva uma mensagem para adicionar ao topo do seu hilo de comentários. Posicionar um tópico, incluem diretrizes comunitárias, etc." include_text: "Inclua seu texto aqui:" include_question_here: "Escreva sua pergunta aqui:" moderate: Moderar moderation_settings: "Configurações de moderação" - open: "Abra" - open_stream: "Abra hilo de comentários" - open_stream_configuration: "Esse hilo de comentários está aberto no momento. Ao fechar este hilo de comentários, nenhum novo comentário pode ser enviado e todos os comentários anteriores ainda serão exibidos." + open: "Abrir" + open_stream: "Abrir comentários" + open_stream_configuration: "Comentários abertos no momento. Ao fechar esta lista de comentários, nenhum novo comentário poderá ser enviado. Mas os comentários anteriores ainda serão exibidos." require_email_verification: "Requerer verificação de email" require_email_verification_text: "Novos usuários devem verificar seu e-mail antes de comentar" save_changes: "Salvar alterações" @@ -125,7 +134,7 @@ pt_BR: stories: Histórias stream_settings: "Configurações de comentários" suspect_word_title: "Lista de palavras suspeitas" - suspect_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão destacados no hilo de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar. Opcionalmente cole uma lista separada por vírgulas." + suspect_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão automaticamente removidos da lista de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar ou cole uma lista separada por vírgulas." tech_settings: "Configurações técnicas" title: "Configurar comentários" weeks: Semanas @@ -135,7 +144,7 @@ pt_BR: check_the_form: "Formulário inválido. Verifique as entradas do formulário." continue: "Continue com o mesmo nome de usuário do Facebook" error_create: "Erro ao alterar o nome de usuário" - fake_comment_body: "Este é um exemplo de comentário. Os leitores podem compartilhar seus pensamentos e opiniões com as salas de redação na seção de comentários." + fake_comment_body: "Este é um exemplo de comentário. Os leitores podem compartilhar seus pensamentos e opiniões com a redação na seção de comentários." fake_comment_date: "1 minuto atrás" if_you_dont_change_your_name: "Se você não alterar seu nome de usuário nesta etapa, seu nome de exibição do Facebook aparecerá ao lado de todos os seus comentários." required_field: "Requerido" @@ -145,30 +154,32 @@ pt_BR: write_your_username: "Edite seu nome de usuário" your_username: "Nosso nome de usuário aparece em todos os comentários que você publica." dashboard: - auto_update: "Data automatically updates every five minutes or when you Reload." + auto_update: "Atualizado autimaticamente a cada minutos ou após recarregamento." comment_count: comentários - flags: Marcadas - most_flags: "Histórias com a maioria das marcadas" - most_conversations: "Histórias com a maioria das conversas" + flags: Marcações + most_flags: "Conversas com mais comentários marcados" + most_conversations: "Conversas com mais comentários" next_update: "{0} minutos até a próxima atualização." no_activity: "Não houve nenhum comentário nos últimos cinco minutos." - no_flags: "Não houve nenhuma marcada em nenhum lugar nos últimos 5 minutos. Hip Hip Uha!" - no_likes: "Não houve gostos nos últimos 5 minutos." + no_flags: "Não houve nenhum comentário marcado em nenhum lugar nos últimos 5 minutos. Hip Hip Uha!" + no_likes: "Não houve reações nos últimos 5 minutos." done: Feito edit_comment: body_input_label: "Edite este comentário" save_button: "Salvar alterações" edit_window_expired: "Você não pode mais editar esse comentário. A janela de tempo para fazê-lo expirou. Por que não publicar outro?" edit_window_expired_close: "Fechar" - edit_window_timer_prefix: "Para editar:" + edit_window_timer_prefix: "Tempo para editar:" second: "segundo" seconds_plural: "segundos" + minute: "minuto" + minutes_plural: "minutos" email: confirm: has_been_requested: "Uma confirmação de e-mail foi solicitada para a seguinte conta:" - to_confirm: "Para confirmar a conta, visite o seguinte link: " + to_confirm: "Para confirmar a conta, visite este link: " confirm_email: "Confirme e-mail" - if_you_did_not: "Se você não solicitou isso, você pode ignorar este e-mail com segurança." + if_you_did_not: "Se você não solicitou isso, você pode ignorar este e-mail." subject: "Confirmação de e-mail" password_reset: we_received_a_request: "Recebemos um pedido para redefinir sua senha. Se você não solicitou esta alteração, pode ignorar este e-mail." @@ -177,7 +188,7 @@ pt_BR: embedlink: copy: "Copiar para área de transferência" error: - COMMENT_TOO_SHORT: "Seu comentário deve conter palavras." + COMMENT_TOO_SHORT: "Seu comentário precisar ter mais de um caracter. Revise seu comentário e envie novamente" NOT_AUTHORIZED: "Você não está autorizado a executar esta ação." NO_SPECIAL_CHARACTERS: "Nomes de usuários podem conter números de letras e _ somente" PASSWORD_LENGTH: "A senha é muito curta" @@ -189,7 +200,7 @@ pt_BR: SAME_USERNAME_PROVIDED: "Você deve enviar um nome de usuário diferente." EMAIL_IN_USE: "Endereço de e-mail já está em uso." EMAIL_REQUIRED: "É necessário o endereço de e-mail." - LOGIN_MAXIMUM_EXCEEDED: "Você fez muitas tentativas de senha mal sucedidas. Por favor, espere." + LOGIN_MAXIMUM_EXCEEDED: "Você fez muitas tentativas de senha mal sucedidas. Espere alguns instantes." PASSWORD_REQUIRED: "Você deve inserir uma senha." COMMENTING_CLOSED: "Os comentários já estão fechados." NOT_FOUND: "Recurso não encontrado" @@ -208,8 +219,8 @@ pt_BR: flag_reason: "Motivo do relatório (opcional)" flag_username: "Informe o nome de usuário" framework: - banned_account_header: "Sua conta está atualmente proibida." - banned_account_body: "Isso significa que você não pode gostar, informar ou escrever comentários." + banned_account_header: "Sua conta está atualmente banida." + banned_account_body: "Isso significa que você não pode curtir, informar ou escrever comentários." comment: comentário comment_is_ignored: "Este comentário está oculto porque você ignorou esse usuário." comments: comentários @@ -241,7 +252,7 @@ pt_BR: account: "contas marcadas" actions: Ações all: todos - all_streams: "Todos os hilos" + all_streams: "Todas as listas" notify_edited: '{0} editou o comentário "{1}"' notify_accepted: '{0} aprovou o comentário "{1}"' notify_rejected: '{0} rejeitou o comentário "{1}"' @@ -252,17 +263,17 @@ pt_BR: billion: B close: Fechar dont_like_username: "Eu não gosto desse nome de usuário" - empty_queue: "Não há mais comentários para moderar! Você está todo apanhado. Vá tomar um ☕️" + empty_queue: "Não há mais comentários para moderar! Aproveite para relaxar e esticar as pernas" flagged: marcado impersonating: Representação less_detail: "Menos detalhes" - likes: gostos + likes: Curtidas million: M - mod_faster: "Moderado mais rápido com atalhos de teclado" + mod_faster: "Modere mais rápido com atalhos de teclado" moderate: "Moderar →" more_detail: "Mais detalhes" new: "Novo" - newest_first: "Mais novo primeiro" + newest_first: "Mais novos primeiro" navigation: Navegação next_comment: "Vá para o próximo comentário" offensive: Ofensiva @@ -272,7 +283,7 @@ pt_BR: prev_comment: "Vá para o comentário anterior" reject: "Rejeitar" rejected: "Rejeitado" - select_stream: "Selecione hilo" + select_stream: "Selecione a lista" shift_key: "⇧" shortcuts: "Atalhos" show_shortcuts: "Ver atalhos" @@ -280,13 +291,13 @@ pt_BR: spam_ads: Spam/Anuncios thismenu: "Abra este menu" thousand: k - try_these: "Tente esse" + try_these: "Tente este" view_more_shortcuts: "Ver mais atalhos" my_comment_history: "Histórico de comentários" name: Nome no_agree_comment: "Eu não concordo com este comentário" - no_like_bio: "Eu não gosto dessa biografia" - no_like_username: "Eu não gosto desse nome de usuário" + no_like_bio: "Eu não gosto dessa descrição de perfil" + no_like_username: "Eu não gosto deste nome de usuário" other: Outro permalink: Link personal_info: "Este comentário revela informações de identificação pessoal" @@ -294,10 +305,10 @@ pt_BR: profile: Perfil profile_settings: "Configurações de perfil" reply: Responder - report: Reportar - report_notif: "Obrigado por reportar este comentário. Nossa equipe de moderação foi notificada e irá revisá-la em breve." - report_notif_remove: "Seu marcado foi removido." - reported: Reportado + report: Denunciar + report_notif: "Obrigado por denunciar este comentário. Nossa equipe de moderação foi notificada e irá revisá-la em breve." + report_notif_remove: "O comentário que você denunciou foi removido." + reported: Denunciado settings: from_settings_page: "Na página de Perfil, você pode ver seu histórico de comentários." my_comment_history: "Histórico de comentários" @@ -316,30 +327,30 @@ pt_BR: all: Todos article: História closed: Fechado - empty_result: "Nenhum recurso corresponde a esta pesquisa. Talvez tente alargar a sua pesquisa?" - filter_streams: "Filtra os hilos" + empty_result: "Nenhum resultado encontrado para esta pesquisa. Que tal refazer a pesquisa com termos diferentes?" + filter_streams: "Filtra as listas" newest: O mais novo oldest: O mais velho open: Aberto pubdate: "Data de publicação" search: Pesquisar sort_by: "Ordenar por" - status: "Status do hilo" - stream_status: "Status do hilo" + status: "Situação dos comentários" + stream_status: "Situação dos comentários" suspenduser: title_suspend: "Suspender usuário" - description_suspend: "Você está suspendendo {0}. Este comentário irá para a fila Rejeitada, e {0} não poderá gostar, reportar, responder ou publicar até que o tempo de suspensão seja concluído." + description_suspend: "Você está suspendendo {0}. Este comentário irá para a fila Rejeitada, e {0} não poderá gostar, denunciar, responder ou publicar até que o tempo de suspensão seja concluído." select_duration: "Selecione a duração da suspensão" one_hour: "1 hora" hours: "{0} horas" days: "{0} dias" cancel: "Cancelar" suspend_user: "Suspender usuário" - email_message_suspend: "Querido/a {0},\n\nDe acordo com as diretrizes da comunidade de {1}, sua conta foi temporariamente suspensa. Durante a suspensão, você não poderá comentar, reportar ou se envolver com outros comentaristas. Por favor, volte para a conversa {2}." + email_message_suspend: "Querido/a {0},\n\nDe acordo com as diretrizes da comunidade de {1}, sua conta foi temporariamente suspensa. Durante a suspensão, você não poderá comentar, denunciar ou se responder outros usuários(as). Por favor, volte para a conversa {2}." title_notify: "Notificar o usuário da suspensão temporária" notify_suspend_until: "O usuário {0} foi temporariamente suspenso. Esta suspensão terminará automaticamente {1}." description_notify: "Suspender este usuário temporariamente desativará sua conta e esconderá todos os seus comentários no site" - write_message: "Escrive uma mensagem" + write_message: "Escrever uma mensagem" send: Enviar reject_username: username: nome de usuário @@ -350,14 +361,14 @@ pt_BR: title_reject: "Percebemos que você rejeitou um nome de usuário" suspend_user: "Suspender usuário" yes_suspend: "Sim suspender" - email_message_reject: "Outro membro da comunidade recentemente sinalizou seu nome de usuário para revisão. Por causa do seu conteúdo, seu nome de usuário foi rejeitado. Isso significa que você não pode mais comentar, gostar, ou reportar conteúdo até que você reescreva seu nome de usuário. Por favor envie-nos um e-mail se tiver dúvidas ou preocupações." + email_message_reject: "Outro membro da comunidade recentemente sinalizou seu nome de usuário para revisão. Por causa do seu conteúdo, seu nome de usuário foi rejeitado. Isso significa que você não pode mais comentar, gostar, ou denunciar conteúdo até que você reescreva seu nome de usuário. Por favor envie-nos um e-mail se tiver dúvidas ou preocupações." write_message: "Escreve uma mensagem" send: Enviar - thank_you: "Nós valorizamos sua segurança e feedback. Um moderador irá rever o seu relatório." + thank_you: "Nós valorizamos sua segurança e opinião. Um moderador irá rever o seu relatório." user: - bio_flags: "Marcadas para esta biografia" - user_bio: "Biografia do usuário" - username_flags: "Marcadas para este nome de usuário" + bio_flags: "Marcadas para este perfil" + user_bio: "Perfil do usuário" + username_flags: "Marcadas para este usuário" user_impersonating: "Este usuário está representando" user_no_comment: "Você nunca deixou um comentário. Participe da conversa!" username_offensive: "Esse nome de usuário é ofensivo" diff --git a/package.json b/package.json index f8c8c9731..57abb4f1d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "build-watch": "WEBPACK=TRUE NODE_ENV=development webpack --progress --config webpack.config.js --watch", "lint": "eslint --ext=.js --ext=.json bin/* .", "lint-fix": "yarn lint --fix", - "test": "TEST_MODE=unit NODE_ENV=test mocha -R ${MOCHA_REPORTER:-spec}", + "jest-watch": "TEST_MODE=unit NODE_ENV=test jest --watch", + "test": "TEST_MODE=unit NODE_ENV=test jest && TEST_MODE=unit NODE_ENV=test mocha -R ${MOCHA_REPORTER:-spec}", "test-cover": "TEST_MODE=unit NODE_ENV=test istanbul cover _mocha --report text --check-coverage -- -R spec", "heroku-postbuild": "./bin/cli plugins reconcile && yarn build", "generate-introspection": "WEBPACK=TRUE NODE_ENV=test ./scripts/generateIntrospectionResult.js" @@ -159,6 +160,7 @@ "react-redux": "^4.4.5", "react-router": "^3.0.0", "react-tagsinput": "^3.17.0", + "react-test-renderer": "15.5", "react-toastify": "^1.5.0", "react-transition-group": "^1.1.3", "recompose": "^0.23.1", @@ -179,17 +181,24 @@ "url-search-params": "^0.9.0", "uuid": "^3.1.0", "webpack": "^2.3.1", + "webpack-sources": "^1.0.1", "yaml-loader": "^0.4.0", "yamljs": "^0.2.10" }, "devDependencies": { - "@coralproject/eslint-config-talk": "^0.0.3", + "@coralproject/eslint-config-talk": "^0.0.4", + "babel-jest": "^21.2.0", + "babel-plugin-dynamic-import-node": "^1.1.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", "chai-http": "^3.0.0", - "enzyme": "^2.9.1", + "enzyme": "^3.0.0", + "enzyme-adapter-react-15": "^1.0.0", "eslint": "^4.5.0", "eslint-plugin-mocha": "^4.11.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^21.2.1", "mocha": "^3.1.2", "mocha-junit-reporter": "^1.12.1", "nodemon": "^1.11.0", diff --git a/plugins/talk-plugin-auth/client/components/ForgotContent.js b/plugins/talk-plugin-auth/client/components/ForgotContent.js index 916c3f5b3..d8ae2fab0 100644 --- a/plugins/talk-plugin-auth/client/components/ForgotContent.js +++ b/plugins/talk-plugin-auth/client/components/ForgotContent.js @@ -1,14 +1,23 @@ import React from 'react'; +import PropTypes from 'prop-types'; import styles from './styles.css'; -import {Button} from 'plugin-api/beta/client/components/ui'; +import {Button, TextField} from 'plugin-api/beta/client/components/ui'; import t from 'coral-framework/services/i18n'; class ForgotContent extends React.Component { + + state = {value: ''}; + handleSubmit = (e) => { e.preventDefault(); - this.props.fetchForgotPassword(this.emailInput.value); + this.props.fetchForgotPassword(this.state.value); }; + handleChangeEmail = (e) => { + const {value} = e.target; + this.setState({value}); + } + render() { const {changeView, auth} = this.props; const {passwordRequestSuccess, passwordRequestFailure} = auth; @@ -20,13 +29,14 @@ class ForgotContent extends React.Component {
- - (this.emailInput = input)} - type="text" +