Code Monkey home page Code Monkey logo

rumors-site's Introduction

rumors-site

CI test Coverage Status

Rumors list / creation UI, with server-side rendering.

Configuration

For development, copy .env.sample to .env and make necessary changes.

For production via rumors-deploy, do setups in docker-compose.yml.

Development

This project uses NodeJS 16. Use a node version manager like nvm to install version 16 (ex. nvm install 16)

$ npm install
$ npm run dev # Then visit http://localhost:3000

# Before you pull request, please lint your code first
$ npm run lint
# fix eslint
$ npm run lint:fix
# run test
$ npm t

styled-jsx syntax highlighting

See: https://github.com/zeit/styled-jsx#syntax-highlighting

Try built image on local

Build docker image.

# build en version
$ docker build --build-arg APP_ID=RUMORS_SITE --build-arg LOCALE=en_US -t rumors-site-test-en .
# build tw version
$ docker build --build-arg APP_ID=RUMORS_SITE --build-arg LOCALE=zh_TW -t rumors-site-test-tw .

This will build both rumors-site-test image.

Run the docker image on local machine, then visit http://localhost:3000.

# English version:
$ docker run --rm --env-file .env -e NODE_ENV=production -p 3000:3000 rumors-site-test-en

# zh_TW version:
$ docker run --rm --env-file .env -e NODE_ENV=production -p 3000:3000 rumors-site-test-tw

Storybook

We use storybook to demonstrate components.

# run storybook localserver on port 6006
$ npm run storybook

we also use storyshot to do snapshot test with stories, make sure to run:

$ npm test -- -u

before pushing to update stories snapshots. Storybook will be available under /storybook/index.html after build.

Analytics

This project supports Google Tag Manager. You can prepare the following setup in .env file:

  • PUBLIC_GTM_ID: Google Tag Manager Container ID (GTM-XXXXXXX)

The application will fire the following custom events in GTM dataLayer:

  • routeChangeStart - when next-router starts route change
  • routeChangeComplete - when next-router finish route change
  • dataLoaded - when article / reply is loaded in article & reply page

Also, it will push the following custom variable to dataLayer;

  • CURRENT_USER - Current user object, set by useCurrentUser.
  • doc - Set when dataLoaded event fires. The loaded content itself in object, including its __typename.

Lastly, in Google Tag Manager we use data-ga property to track clicks. If user clicks a decendant of an React element with data-ga property, a click event will be sent to Google analytics with the written data-ga. (It doesn't even need to be rendered, we setup the Google Tag Manager to read private React instance)

Also, if a component has its displayName set, a click event with that displayName is also sent to Google Analytics when any of its decendant is clicked.

Design and Mockups

Translation

We use ttag to support build-time i18n for the SSR website. During deploy, we build one Docker image for each locale.

Please refer to ttag documentation for annotating strings to translate.

To extract annotated strings to translation files, use:

$ npm run i18n:extract

Translation files

The translation files are located under i18n/, in Gettext PO format.

  • en_US.po: Since the language used in code is already English, this empty translation file exists to simplify settings.
  • zh_TW.po: Traditional Chinese translation.
  • ja.po: Japanese translation.

Supporting other languages

You can replace this with any language you want to support, by leveraging Gettext msginit command.

You will need to change the following to reflect the locale change:

  • i18n:extract script in package.json
  • i18n:validate script in package.json

Building in different languages

By default, the chatbot will be built under en_US locale.

During development, changing LOCALE in .env allows you to spin up dev server under a specific locale. Please set LOCALE to one of en_US, zh_TW or any other language code that exists under i18n/ directory.

When previewing translated site on local machine, sometimes the translated text does not appear. You may need to set BABEL_DISABLE_CACHE (example: BABEL_DISABLE_CACHE=1 npm run dev) to disable babel cache for the new translation to appear correctly.

When building using Docker, LOCALE can be provided via build args.

Typescript and API types

This repository uses GraphQL Code Generator with client preset.

When writing Typescript file with GraphQL, please run this command to generate or update the GraphQL codegen result (TypedDocumentNode in typegen/*):

$ npm run typegen

If encountering GraphQL operations or fragments wrapped with gql, please change to codegen result instead:

// Old syntax
import gql from 'graphql-tag';

gql`...`;

// New syntax
import { graphql } from 'path-to-typegen';
graphql(/* GraphQL */ `...`)

To consume the fragments from typed API, see Fragment Masking documentation of the client preset.

Legal

LICENSE defines the license agreement for the source code in this repository.

LEGAL.md is the user agreement for Cofacts website users.

rumors-site's People

Contributors

agameofprivacy avatar ajua avatar ben196888 avatar dependabot[bot] avatar enninglintw avatar fufushih avatar godgunman avatar gorestarry avatar hsiao19 avatar jihchi avatar johnson-liang avatar kelvin2go avatar leannechen avatar lucienlee avatar marcussfu avatar mrorz avatar nonumpa avatar normanlinnet avatar ooookai avatar quad avatar renovate-bot avatar simonzheng avatar stimim avatar su-ya avatar tucchhaa avatar ulayab avatar yanglin5689446 avatar young-tw avatar yumichen avatar ztsai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

rumors-site's Issues

Reply list page

List:

  1. latest replies added to the database (sorting)
  2. My replies (filtering)

Trendlines of an article

Display a 7-day trend line to visualize the popularity of an article.

Use reply requests counts, reply feedback counts and LINE bot searches counts (via Google analytics API) to build up the chart.

We can use this to make charts:
https://aftertheflood.co/projects/sparks/

Reference:

"24HR trend" in rollbar item list page
2018-05-11 10 57 38

在文章頁面加上「求回應」按鈕

需要登入。
讓網站使用者也能送出 replyRequest。

按鈕位置:
2019-03-06 10 40 20

點按過後:
reson-submit

copy:

    <p>請告訴其他編輯:<strong>您為何覺得這是一則謠言</strong>?</p>
    <textarea placeholder="例:我用 OO 關鍵字查詢 Facebook,發現⋯⋯ / 我在 XX 官網上找到不一樣的說法如下⋯⋯"></textarea>
    <details>
    <summary>送出理由小撇步</summary>
你可以試著:<br>
A. 闡述更多想法<br>
B. 去 google 查查看<br>
C. 把全文複製貼上到 Facebook 搜尋框看看<br><br>
把你的結果傳給其他編輯參考吧!
</details>
    <button disabled="">字數太少,無法送出</button>

</div>

Redirect http to https

  1. Change CORS rule to use https for rumors.hacktabl.org
  2. Redirect http ones to https using cloudflare page rules

[Gamification] Show overall progress bar

In the site header, show a progress bar with 3 racing indicators:

  1. The number of articles that has been replied
  2. The number of total articles
  3. The number of articles the user has replied ( API: cofacts/rumors-api#74 )
| ============================> Total articles: 16,321
| =======================:---> Replied by others: 15900 / by you: 321

With the following nice-to-have:

  • When the user submits an article, show a "+1" effect on the "The number of articles that has been replied" or "The number of articles the user has replied"
  • The number is updated whenever the user changes page. (No +1 effect in this case)

500 internal server error when clicking into an article

Visit: https://cofacts.g0v.tw/article/AWEET-BFyCdS-nWhunGr

TypeError: Cannot read property 'set' of null
    at /srv/www/.next/dist/ducks/articleDetail.js:182:35
    at /srv/www/node_modules/immutable/dist/immutable.js:3016:46
    at List.__iterate (/srv/www/node_modules/immutable/dist/immutable.js:2206:13)
    at IndexedIterable.mappedSequence.__iterateUncached (/srv/www/node_modules/immutable/dist/immutable.js:3015:23)
    at seqIterate (/srv/www/node_modules/immutable/dist/immutable.js:604:16)
    at IndexedIterable.IndexedSeq.__iterate (/srv/www/node_modules/immutable/dist/immutable.js:320:14)
    at IndexedIterable.toArray (/srv/www/node_modules/immutable/dist/immutable.js:4258:23)
    at List [as constructor] (/srv/www/node_modules/immutable/dist/immutable.js:2065:62)
    at reify (/srv/www/node_modules/immutable/dist/immutable.js:3570:37)
    at List.map (/srv/www/node_modules/immutable/dist/immutable.js:4401:14)

L172 - 197

return state.withMutations(function (s) {
    return s.updateIn(['data', 'article'], function (article) {
      return (article || (0, _immutable.Map)()).merge(payload.remove('replyConnections').remove('relatedArticles'));
    }).setIn(['data', 'replyConnections'], payload.get('replyConnections')).updateIn(['data', 'relatedArticles'], function (articles) {
      return !relatedArticleEdges.size ? articles : relatedArticleEdges.map(function (edge) {
        return edge.get('node').remove('replyConnections');
      });
    }).updateIn(['data', 'relatedReplies'], function (replies) {
      return !relatedArticleEdges.size ? replies : relatedArticleEdges.flatMap(function (edge) {
        return edge.getIn(['node', 'replyConnections']).map(function (conn) {
          return conn.get('reply').set('article', edge.get('node').remove('replyConnections'));
        }).filter(function (reply) {
          // Filter-out replies that is already re-used.
          return reply && !replyIds.contains(reply.get('id'));
        });
      })
      // De-duping replies using replyId, taking the reply with more relavant article
      // (which should come first)
      //
      .groupBy(function (reply) {
        return reply.get('id');
      }).map(function (replyGroup) {
        return replyGroup.first();
      }).toList();
    });
  });

L182: return conn.get('reply').set('article', edge.get('node').remove('replyConnections'));

調整文章頁面的回應順序,使得與 LINE 一致

Line bot 的顯示順序是:

  1. 有幾則回應認為含有真實訊息、有幾則認為含有不實訊息
  2. 先列出認為真實的
  3. 然後列出認為不實的

或者是可以做成分頁的形式。

這樣可以讓不同立場的聲音更容易被拿來對比與看見。

URIError: URI malformed

View details in Rollbar: https://rollbar.com/mrorz/rumors-site/items/3/


URIError: URI malformed
  File "<anonymous>", line unknown, in decodeURIComponent
  File "/srv/www/node_modules/next-routes/dist/index.js", line 233, in <unknown>
            return Object.assign(params, _defineProperty({}, _this4.keys[i].name, decodeURIComponent(val)));
  File "<anonymous>", line unknown, in Array.reduce
  File "/srv/www/node_modules/next-routes/dist/index.js", line 231, in Route.valuesToParams
          return values.reduce(function (params, val, i) {
  File "/srv/www/node_modules/next-routes/dist/index.js", line 223, in Route.match
            return this.valuesToParams(values.slice(1));
  File "/srv/www/node_modules/next-routes/dist/index.js", line 96, in routes.reduce.query
            var params = route.match(pathname);
  File "<anonymous>", line unknown, in Array.reduce
  File "/srv/www/node_modules/next-routes/dist/index.js", line 94, in Routes.match
          return this.routes.reduce(function (result, route) {
  File "/srv/www/node_modules/next-routes/dist/index.js", line 126, in <unknown>
            var _match2 = _this.match(req.url),
  File "/srv/www/server.js", line 60, in server.use
        handler(ctx.req, ctx.res);

Article page pagination issue

The total number of 2nd ajax loaded article page is wrong. It shows "0 articles" and Prev/Next link disappears.

pagination

Note that reply page does not have such bug.

Enhance "NOT ARTICLE" functionality

  • 改名「不在查證範圍」
  • 新增樣板「這是廣告活動,活動期間到⋯⋯」引導編輯填寫活動時間,但編輯也可以不填。
  • 新增樣板「訊息僅含有失效連結」
  • 編輯界面增加「查證範圍」連結(for 編輯);當有回應是「不在查證範圍」時,提供使用者一個連結說「查證範圍是什麼」(for 使用者)

Show URL preview in website

We will collect hyperlinks & their info in DB it should be accessible via API ( cofacts/rumors-api#41 ).

We should show part of such info in article page so that the editors can have a glimpse of the content of the page without clicking into the site.

Add reply request filter to article list

"Show only articles with <input> reply requests"
「只顯示至少 <input> 人回報的文章」

Implements as a checkbox below "Not replied yet / Replied / All" radio buttons

This is blocked by cofacts/rumors-api#54, which will implement the API needed for this function.

讓使用者在網站上用關鍵字搜尋謠言

現在的狀況是,我常常想要找含有「醫藥」或「年金」兩字的謠言,但網頁目前卻沒有搜尋框。

或許用現成 Search API 可行?

比較一下 ListArticle 與 Search 的差異,應該可以直接使用,不須在 Search 加一個 input 欄位。

Add a "share" or "copy to clipboard" button in each reply

Use cases

  1. Users found the desired reply on cofacts.g0v.tw and want to share to LINE or other places.
  2. Editors found a reply to copy from when replying other articles.

Currently, the user will have to copy "含有真實訊息" / "含有不實訊息", the reasons and the references separately. When the URL in the references are too long, the URLs gets truncated, and will become unusable after paste.

Proposed solution

Add a "Share" or "Copy to clipboard" button to each replies. (Article page)
2019-03-06 10 31 50

For example, in an article page like this:
https://cofacts.g0v.tw/article/AV_pZ0PPyCdS-nWhujrf

When the 'share' or 'copy to clipboard' button is pressed, the following text should be shared or put in to the clipboard:

⭕ 含有正確訊息

理由:
尋人持續進行中。

出處:
https://www.facebook.com/permalink.php?story_fbid=1677448952276114&id=100000330760687
尋人
https://www.youtube.com/watch?v=yad0JzYfzuY&feature=youtu.be
女大生離家失蹤4天

---
看看其他回應:https://cofacts.g0v.tw/article/AV_pZ0PPyCdS-nWhujrf

Tech reference

Native "share" on Google Chrome mobile:
https://developers.google.com/web/updates/2016/09/navigator-share

Cross-browser clipboard solution
https://clipboardjs.com/

Dealing with "Spammy structured markup"

2017-11-29 1 40 48

I think maybe we are doing "fact-check tags" wrong. We should first remove the tags and see if this error goes away, then re-implements the fact-check tags in a different manner.

[Gamification] show level & the level name for each user when hovering on editor's name

  • Show level, level name in the top right corner of the site
  • When hovering over an editor's name, show a info card with their level name
  • When the user "levels up", show a small popup prompting the user about it

API for level: cofacts/rumors-api#73

Level name list:

lv0 從零開始的主人公
lv1 鄉民
lv2 站得前面一點的鄉民
lv3 好心人
lv4 很好心的人
lv5 好人
lv6 大好人
lv7 謠民(背號11,要改11嗎)
lv8 童貞魔法師
lv9 老司機
lv10 闢謠天行者
lv11 魔法少女(200得貼圖)
lv12 闢謠天師(闢謠太帥)
lv13 謠言大覺者(400有貼圖)
lv14 謠言終結者(800送貼圖)
lv15 滅謠師太
lv16 闢謠小女警
lv17 闢謠小飛俠
lv18 闢謠鐵金剛
lv19 從零開始的魔法旋轉花花
lv20 變態的好人
lv21 超能孟獲
lv22 熱血傲嬌律師
lv23 初號機
lv24 貳號機
lv25 好心神

Show the reasons of submitting articles and allow voting on the reasons

Cause

According to the discussions in "詢問爭點功能", we should reveal the reasons why a LINE user want to submit such article to the editors.

Requirement

  • In the article page, list the reasons for each reply requests
  • For each reason, allow editors to upvote / downvote. Ask the editor if the reason is useful for you to understand the question / where the controversy is.
  • Allow users to edit their upvote / downvote

Resources

The article object type will soon support replyrequests field, in which has reason field and the feedback voting fields. Also, we will support CreateReplyRequestFeedback API.

Related API: cofacts/rumors-api#69

謠言列表頁面

謠言列表�頁面設計開發:

  • Filter/ Sort
  • Search bar
  • Article Summary
  • Tags

Code quality refactor items

  • Simplify app() HOC: should invoke page components' getInitialProps instead of initFn, directly put bootstrapFn in page component's componentDidMount. Integrate redux stuff to _app.js, since we are migrating to next6 in #106 . Reference: _app usage , next-redux-wrapper integration & implementation
  • Add storybook for components. Document the properties and setup snapshots. Add the following addons:
    • storyshots
    • storysource
    • info
    • jest
  • Replace all replyConnections with articleReplies

List all articles the current author has submitted

Cause

As discussed in 20180207 "使用者發送過的文章列表" section, we should provide a list of articles a LINE user has submitted.

Requirements

  • Add a "Author of article" text box in the filter section of current article list page, which allows the user to input an article ID.
  • Add a link to "list all submitted articles of this user" in single article page -- @LucienLee please help determine where the link should be put on page
  • The user clicks the link, the the user will be directed to article page, with a filter "Author of article" checked and filled with the ID of the visited article.

Resources

The API will support "Given an article, list all articles the current author has submitted" via the new
fromUserOfArticleId filter in ListArticles.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.