├── .gitignore
├── README.md
├── assets
└── intro.gif
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
└── src
├── actions
└── fetchDataAction.js
├── components
├── Analysis.js
├── App.js
├── Filter.js
├── Home.js
├── Results.js
└── WordCloudRender.js
├── css
├── App.css
├── Home.css
├── Results.css
├── Search.css
├── WordCloudRender.css
└── index.css
├── index.js
├── reducers
├── fetchProjNamesReducer.js
├── fetchProjVarReducer.js
├── index.js
└── wordCloudReducer.js
└── store.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Javascript Popular Variable Frontend
2 | Ever had trouble naming your variable or function names? Wonder how the greatest repository did their naming? Well I made this website so you can search and reference how the most popular Javascript repository's varaible and function names.
3 | The website is deployed [here](https://billcccheng.github.io/js-popular-variable-frontend/).
4 |
5 | ## Demo
6 |
7 |
8 |
9 |
10 |
11 | ## Installation
12 | First clone the repository.
13 | ```
14 | git clone https://github.com/billcccheng/js-popular-variable-frontend.git
15 | ```
16 |
17 | Then `npm install` to install all the required packages. After you have
18 | all the packages installed, you can `npm run start` to play around with you app on `port 8000`.
19 |
20 | ```
21 | npm install
22 | npm run start
23 | ```
24 | If you want to change your port to 8080, just go to `package.json` and change `"start":...` to
25 |
26 | ```
27 | "start": "PORT=8000 react-scripts start"
28 | ```
29 |
30 | ## The Backend Server
31 | * All the logic and searching of the app is loaded on a heroku server. All the source code of the heroku server can be
32 | found [here](https://github.com/billcccheng/js-popular-variable-server)
33 | * Remember to comment out this [line](https://github.com/billcccheng/js-popular-variable-frontend/blob/master/src/actions/fetchDataAction.js#L5) if you want to test the server on your localhost or comment out this [line](https://github.com/billcccheng/js-popular-variable-frontend/blob/master/src/actions/fetchDataAction.js#L4) if you want to use the heroku server.
34 |
35 | ## Change Logs
36 | * 02.03.2018 System is live and up. Alpha Version RUNNING!!!!
37 |
38 | ## Future Update
39 | * Analysis
40 |
41 | ## Contributing
42 | 1. Fork it!
43 | 2. Create your feature branch: `git checkout -b my-new-feature`
44 | 3. Commit your changes: `git commit -am 'Add some feature'`
45 | 4. Push to the branch: `git push origin my-new-feature`
46 | 5. Submit a pull request :smile:
47 | 6. All contributions are **welcomed** :blush:!
48 |
49 | ## Credits
50 | Thanks to
51 | * [bentatum](https://github.com/bentatum/better-react-spinkit) for the wonderful loading icons.
52 | * [Yoctol](https://github.com/Yoctol/react-d3-cloud) for the beautiful word cloud library.
53 | * [JedWatson](https://github.com/JedWatson/react-select) for react dropdown/select library.
54 |
55 | ## License
56 | [MIT license](http://opensource.org/licenses/MIT).
57 |
58 | © 2018 Bill Cheng
59 |
--------------------------------------------------------------------------------
/assets/intro.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/billcccheng/js-popular-variable-frontend/f803b50194fd480af1489aa7d0ca20e08183f4cb/assets/intro.gif
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "js-popular-variable-frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "./",
6 | "devDependencies": {
7 | "gh-pages": "^1.1.0",
8 | "react-scripts": "1.1.0",
9 | "redux-logger": "^3.0.6"
10 | },
11 | "dependencies": {
12 | "axios": "^0.17.1",
13 | "better-react-spinkit": "^2.0.4",
14 | "d3-cloud": "^1.2.4",
15 | "d3v3": "^1.0.3",
16 | "material-ui": "^1.0.0-beta.30",
17 | "react": "^16.2.0",
18 | "react-d3-cloud": "^0.5.0",
19 | "react-dom": "^16.2.0",
20 | "react-mdl": "^1.11.0",
21 | "react-redux": "^5.0.6",
22 | "react-router-dom": "^4.2.2",
23 | "react-select": "^1.2.1",
24 | "react-spinkit": "^3.0.0",
25 | "react-tagcloud": "^1.2.0",
26 | "redux": "^3.7.2",
27 | "redux-promise-middleware": "^5.0.0",
28 | "redux-thunk": "^2.2.0",
29 | "thunk": "0.0.1"
30 | },
31 | "scripts": {
32 | "start": "PORT=8000 react-scripts start --host=0.0.0.0",
33 | "build": "react-scripts build",
34 | "deploy": "react-scripts build && gh-pages -d build",
35 | "test": "react-scripts test --env=jsdom",
36 | "eject": "react-scripts eject"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/billcccheng/js-popular-variable-frontend/f803b50194fd480af1489aa7d0ca20e08183f4cb/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
18 |
19 | JavaScript Naming
20 |
21 |
22 |
23 |
24 | You need to enable JavaScript to run this app.
25 |
26 |
27 |
28 | Designed in React & Redux by Bill Cheng
29 |
30 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/actions/fetchDataAction.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | /*LOCAL TESTING USE*/
4 | //const hostName = "http://localhost:5000/api";
5 | const hostName = "https://js-popular-variable-server.herokuapp.com/api"
6 |
7 | export function fetchProjectNames() {
8 | return (dispatch) => {
9 | const url = `${hostName}/getProjectNames`;
10 | dispatch({type: "FETCH_PROJECT_NAMES", payload: axios.get(url)});
11 | }
12 | }
13 |
14 | export function fetchWCProjectNames() {
15 | return (dispatch) => {
16 | const url = `${hostName}/fetchWordCloudProjectNames`;
17 | dispatch({type: "FETCH_WC_PROJECT_NAMES", payload: axios.get(url)});
18 | }
19 | }
20 |
21 | export function fetchProjectVariables(selectedProjects, filters, unFetchedProjects=[]) {
22 | return (dispatch, getState) => {
23 | const thisState = getState().fetchProjVarReducer;
24 | const url = `${hostName}/getProjectVariables`;
25 | dispatch({type: "FETCH_PROJECT_VARIABLES_PENDING"});
26 |
27 | if(unFetchedProjects.length === 0) {
28 | const filteredResults = filterResults(thisState.results, selectedProjects, filters);
29 | dispatch({
30 | type: "FETCH_PROJECT_VARIABLES_FULFILLED",
31 | filtered: filteredResults,
32 | results: thisState.results
33 | });
34 | } else {
35 | axios.post(url,{
36 | selectedProjects: unFetchedProjects
37 | }).then((res) => {
38 | const newResults = {...thisState.results, ...res.data}
39 | const filteredResults = filterResults(newResults, selectedProjects, filters);
40 | dispatch({
41 | type: "FETCH_PROJECT_VARIABLES_FULFILLED",
42 | filtered: filteredResults,
43 | results: newResults
44 | });
45 | }).catch((err) => {
46 | dispatch({type: "FETCH_PROJECT_VARIABLES_REJECTED"});
47 | });
48 | }
49 | }
50 | }
51 |
52 | export function simpleFilter(selectedProjects, filters) {
53 | return (dispatch, getState) => {
54 | const thisState = getState().fetchProjVarReducer;
55 | const results = thisState.results;
56 | const filteredResults = filterResults(results, selectedProjects, filters);
57 | dispatch({
58 | type: "FETCH_PROJECT_VARIABLES_FULFILLED",
59 | filtered: filteredResults,
60 | results: results
61 | });
62 | }
63 | }
64 |
65 | export function fetchWCSingleProjectVariables(selectedProject) {
66 | return (dispatch, getState) => {
67 | dispatch({type: "FETCH_WC_PROJECT_VARIABLES_PENDING"});
68 | const thisState = getState().wordCloudReducer;
69 | const savedProject = Object.keys(thisState.wcSavedData);
70 | if(savedProject.indexOf(selectedProject) !== -1){
71 | dispatch({
72 | type: "FETCH_WC_PROJECT_VARIABLES_FULFILLED",
73 | savedResults: thisState.wcSavedData,
74 | resToBeShowed: thisState.wcSavedData[selectedProject]
75 | });
76 | } else {
77 | const url = `${hostName}/getSingleProjectVariables/${selectedProject}`;
78 | axios.get(url).then((res) => {
79 | dispatch({
80 | type: "FETCH_WC_PROJECT_VARIABLES_FULFILLED",
81 | savedResults: {...thisState.wcSavedData, ...{[selectedProject]: res.data}},
82 | resToBeShowed: res.data
83 | });
84 | }).catch((err) => {
85 | dispatch({
86 | type: "FETCH_WC_PROJECT_VARIABLES_REJECTED",
87 | });
88 | });
89 | }
90 | }
91 | }
92 |
93 | export function clearShowResultsTree() {
94 | return (dispatch, getState) => {
95 | dispatch({
96 | type: "CLEAR_FETCH_WC_PROJECT_VARIABLES_SHOW_RESULTS",
97 | });
98 | }
99 | }
100 |
101 | export function wcSimpleFilter(selectedProject, filter) {
102 | return (dispatch, getState) => {
103 | dispatch({type: "FETCH_WC_PROJECT_VARIABLES_PENDING"});
104 | const savedResults = getState().wordCloudReducer.wcSavedData;
105 | const lowerCaseFilter = filter.toLowerCase();
106 | const updatedResults = savedResults[selectedProject].filter((itm) => {
107 | return itm.value.toLowerCase().includes(lowerCaseFilter);
108 | });
109 |
110 | dispatch({
111 | type: "FETCH_WC_PROJECT_VARIABLES_FULFILLED",
112 | resToBeShowed: updatedResults.length !== 0 ? updatedResults : [{ value: "NO RESULTS", count: 1000, url:'https://en.wikipedia.org/wiki/Null_result' }],
113 | savedResults: savedResults
114 | });
115 | }
116 | }
117 |
118 | function filterResults(results, selectedProjects, filterInput) {
119 | const userInput = filterInput.toLowerCase();
120 | let filteredResults = {};
121 | selectedProjects.forEach(projectName => {
122 | projectName = projectName.charAt(0).toLowerCase() + projectName.slice(1);
123 | filteredResults[projectName] = {};
124 | if(projectName in results){
125 | const variableNames = Object.keys(results[projectName]);
126 | variableNames.filter(variableName => {
127 | return variableName.toLowerCase().includes(userInput);
128 | }).map((variableName) => {
129 | filteredResults[projectName][variableName] = results[projectName][variableName];
130 | return filteredResults;
131 | });
132 | }
133 | });
134 | return filteredResults;
135 | }
136 |
--------------------------------------------------------------------------------
/src/components/Analysis.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Analysis extends Component {
4 | render(){
5 | return( Under Construction: Will have some analysis on this tab in the future.
);
6 | }
7 | }
8 |
9 | export default Analysis;
10 |
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import Analysis from "./Analysis";
2 | import Home from "./Home";
3 | import Filter from "./Filter";
4 | import WordCloudRender from "./WordCloudRender";
5 | import "../css/App.css";
6 |
7 | import React, { Component } from "react";
8 | import { Tabs, Tab } from "react-mdl/lib/Tabs";
9 |
10 | class App extends Component {
11 | constructor(){
12 | super();
13 | this.state = {
14 | active: 0
15 | }
16 | }
17 |
18 | onChange(id) {
19 | this.setState({ active: id });
20 | }
21 |
22 | render() {
23 | const tabs = [
24 | {"ActivateComponent": React.createFactory(Home)},
25 | {"ActivateComponent": React.createFactory(Filter)},
26 | {"ActivateComponent": React.createFactory(WordCloudRender)},
27 | {"ActivateComponent": React.createFactory(Analysis)}
28 | ];
29 | return (
30 |
31 |
Find JavaScript Variables
32 |
Note: API server is hosted on HEROKU so it may take some time to boot up the server if the server is sleeping.
33 |
34 |
35 | Home
36 | Filter
37 | Word Cloud
38 | Analysis
39 |
40 |
41 | {tabs[this.state.active].ActivateComponent()}
42 |
43 | );
44 | }
45 | }
46 |
47 | export default App;
48 |
--------------------------------------------------------------------------------
/src/components/Filter.js:
--------------------------------------------------------------------------------
1 | import Results from './Results';
2 | import { fetchProjectNames } from '../actions/fetchDataAction';
3 | import '../css/Search.css';
4 |
5 | import React, { Component } from 'react';
6 | import { Button } from 'react-mdl';
7 | import { connect } from 'react-redux';
8 | import { DoubleBounce } from 'better-react-spinkit';
9 |
10 | class Search extends Component {
11 | constructor() {
12 | super();
13 | this.state = {
14 | selectedProjects: [],
15 | updateResults: false
16 | }
17 | this.selectedProjects = [];
18 | }
19 |
20 | componentWillMount() {
21 | if(!this.props.projectNames.length)
22 | this.props.fetchProjectNames();
23 | }
24 |
25 | submitCheckbox = () => {
26 | if(this.selectedProjects.length > 0) {
27 | this.setState({
28 | selectedProjects: this.selectedProjects,
29 | updateResults: true
30 | });
31 | }
32 | }
33 |
34 | toggleChange = (event) => {
35 | const selectedProject = event.target.name;
36 | const indexOfProject = this.selectedProjects.indexOf(selectedProject);
37 | if(indexOfProject !== -1) {
38 | this.selectedProjects = this.selectedProjects.filter((itm, i) => i !== indexOfProject);
39 | } else {
40 | this.selectedProjects = this.selectedProjects.concat(selectedProject);
41 | }
42 | }
43 |
44 | render() {
45 | if(this.props.isProjectNamesLoading) {
46 | return( );
47 | } else if(this.props.projectNameError) {
48 | return(An Error Occured...Please try again later.
);
49 | } else {
50 | const projectNames = this.props.projectNames;
51 | return(
52 |
53 |
54 | Popluar Javascript Repo
55 |
56 |
57 | Submit
58 |
59 |
60 | {this.state.selectedProjects.length > 0 ?
: null}
61 |
62 | );
63 | }
64 | }
65 | }
66 |
67 | const ProjectCheckboxes = ({names, that}) => {
68 | return(
69 | names.map(name => (
70 |
71 |
76 | {name}
77 |
78 | )
79 | )
80 | );
81 | }
82 |
83 | const mapStateToProps = (state) => {
84 | return {
85 | projectNames: state.fetchProjNamesReducer.projectNames,
86 | isProjectNamesLoading: state.fetchProjNamesReducer.projectNamesIsLoading,
87 | projectNameError: state.fetchProjNamesReducer.fetchProjectNameHasError
88 | }
89 | }
90 |
91 | const mapDispatchToProps = (dispatch) => {
92 | return {
93 | fetchProjectNames: () => dispatch(fetchProjectNames()),
94 | }
95 | }
96 |
97 | export default connect(mapStateToProps, mapDispatchToProps)(Search);
98 |
--------------------------------------------------------------------------------
/src/components/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import '../css/Home.css';
3 |
4 | class Home extends Component {
5 | render(){
6 | return(
7 |
8 |
Why I Started This Project
9 |
10 |
11 | This project extracted the top ten most popular (most stars) JavaScript repo on GitHub and pulled out the function names and variable names. Instructions on how to use this app is on GitHub but believe me - the app is self-explanatory.
12 |
13 |
14 | It's great to use programs like JavaScript and Python which are dynamically typed but sometimes it's just painful when you don't use it the right way. I started this project to help developers who are having difficulties naming there varibles (yes...I've been there a lot of time). Good variable names helps code reviews and produces better software qualities. Below are two real life example that good naming would benefit every software developers in the long run.
15 |
16 |
17 | There was this day when I was code reviewing one of the tickets that was assigned to me. It was a huge ticket and lots of code refactoring. Along the way, I saw this function named checkNextBillingDate . At first I assumed this meant returning back a string or date object. However, diving deeper into the code I found out that variable was returning back a boolean value. WHAT?!?! How does checkNextBillingDate return a boolean? Even if it did, how would I know what it was checking. Well after digging into the function, I finally figured out it was trying to check to check if the date passed in was a future. A better naming would have maybe been isDateInFuture or something like that.
18 |
19 |
20 | The last reason and the most important reason: Since I am not a native English speaker and believe me...naming variable is painful for non native speaker since we don't have the vocabulary size as a native speaker. During my undergraduate years in Taiwan, I had a lot of friends who were naming their variables in all sorts of strange name. To make matters worse: they had invented or misspelled a variable name they thought was something. Reading those code was a nightmare, not saying code reviewing them.
21 |
22 |
23 | To sum it up, I wish the app can be useful for people to reference how popoular repos name their variables or functions. In the end, all good software developer learn from the best codes and I believe that the most popular repos are always a good place to start.
24 |
25 | Bill Cheng
26 |
);
27 | }
28 | }
29 |
30 | export default Home;
31 |
--------------------------------------------------------------------------------
/src/components/Results.js:
--------------------------------------------------------------------------------
1 | import { fetchProjectVariables, simpleFilter } from '../actions/fetchDataAction';
2 | import '../css/Results.css';
3 |
4 | import React, { Component } from 'react';
5 | import { connect } from 'react-redux';
6 | import { DoubleBounce } from 'better-react-spinkit';
7 |
8 | class Results extends Component {
9 | constructor(){
10 | super();
11 | this.receivedProjects = [];
12 | this.filterInput = "";
13 | }
14 |
15 | componentWillMount() {
16 | this.fetchVariableData(this.props.selectedProjects);
17 | }
18 |
19 | componentWillReceiveProps(nextProps) {
20 | if(JSON.stringify(this.props.selectedProjects) !== JSON.stringify(nextProps.selectedProjects)) {
21 | this.fetchVariableData(nextProps.selectedProjects);
22 | }
23 | }
24 |
25 | fetchVariableData(selectedProjects) {
26 | const _receivedProjects = this.receivedProjects;
27 | const unFetchedProjects = selectedProjects.filter(itm => !_receivedProjects.includes(itm))
28 | this.receivedProjects = _receivedProjects.concat(unFetchedProjects);
29 | if(!unFetchedProjects.length) {
30 | this.props.fetchProjectVariables(selectedProjects, this.filterInput, unFetchedProjects);
31 | }
32 | if(unFetchedProjects.length > 0) {
33 | this.props.fetchProjectVariables(selectedProjects, this.filterInput, unFetchedProjects);
34 | }
35 | }
36 |
37 | onFilterChange = (event) => {
38 | if(event.key === 'Enter') {
39 | const newFilterInput = event.target.value.trim();
40 | if(this.filterInput !== newFilterInput) {
41 | this.filterInput = newFilterInput
42 | }
43 | this.props.simpleFilter(this.props.selectedProjects, this.filterInput);
44 | }
45 | }
46 |
47 | render() {
48 | if(this.props.hasError) {
49 | return(An Error Occured...Please try again later.
);
50 | }
51 |
52 | if(this.props.isLoading) {
53 | return( );
54 | } else {
55 | const results = this.props.filteredResults;
56 | const projectNames = Object.keys(results);
57 | return(
58 |
67 | );
68 | }
69 | }
70 | }
71 |
72 | const ProjectVariableList = ({projectNames, results}) => {
73 | return (
74 | projectNames.map(projectName =>
75 |
76 |
{projectName.toUpperCase()}
77 |
78 | {Object.keys(results[projectName]).map(variableName =>
79 | {variableName} )
80 | }
81 |
82 |
83 | )
84 | );
85 | }
86 |
87 | const mapStateToProps = (state) => {
88 | return {
89 | results: state.fetchProjVarReducer.results,
90 | filteredResults: state.fetchProjVarReducer.filteredResults,
91 | isLoading: state.fetchProjVarReducer.isLoading,
92 | hasError: state.fetchProjVarReducer.hasError
93 | }
94 | }
95 |
96 | const mapDispatchToProps = (dispatch) => {
97 | return {
98 | fetchProjectVariables: (projects, filters, unFetchedProjects) => dispatch(fetchProjectVariables(projects, filters, unFetchedProjects)),
99 | simpleFilter: (selectedProjects, filters) => dispatch(simpleFilter(selectedProjects, filters))
100 | }
101 | }
102 |
103 | export default connect(mapStateToProps, mapDispatchToProps)(Results);
104 |
--------------------------------------------------------------------------------
/src/components/WordCloudRender.js:
--------------------------------------------------------------------------------
1 | import { fetchWCProjectNames, fetchWCSingleProjectVariables } from "../actions/fetchDataAction";
2 | import { wcSimpleFilter, clearShowResultsTree } from "../actions/fetchDataAction";
3 | import "../css/WordCloudRender.css";
4 |
5 | import React, { Component } from "react";
6 | import Select from "react-select";
7 | import { TagCloud } from "react-tagcloud";
8 | import { connect } from "react-redux";
9 | import { DoubleBounce } from "better-react-spinkit";
10 | import "react-select/dist/react-select.css";
11 |
12 | class WordCloudRender extends Component {
13 | constructor() {
14 | super();
15 | this.filterInput = "";
16 | }
17 |
18 | componentWillMount() {
19 | if(!this.props.wcProjectNames.length) {
20 | this.props.fetchWCProjectNames();
21 | }
22 | this.selectedProject = "";
23 | }
24 |
25 | componentWillUnmount() {
26 | this.props.clearShowResultsTree();
27 | }
28 |
29 | onSelectChange = (selectedProject) => {
30 | this.selectedProject = selectedProject.value;
31 | const recievedProjects = this.props.wcSavedProjects;
32 | if(recievedProjects.indexOf(selectedProject.value) !== -1) {
33 | this.props.wcSimpleFilter(this.selectedProject, this.filterInput);
34 | } else {
35 | this.props.fetchWCSingleProjectVariables(this.selectedProject);
36 | }
37 | }
38 |
39 | onFilterChange = (event) => {
40 | if(event.key === "Enter") {
41 | const newFilterInput = event.target.value.trim();
42 | this.filterInput = newFilterInput;
43 | this.props.wcSimpleFilter(this.selectedProject, this.filterInput);
44 | }
45 | }
46 |
47 | render() {
48 | const color = {luminosity: 'dark', hue: 'blue'};
49 | return(
50 |
51 |
52 |
53 | Node has been excluded in word cloud due to it's large volume of variables.
54 | Click on the word to take you to the Github search.
55 |
56 |
57 |
68 | {!this.props.wcIsLoading && this.props.wcShowResults.length > 0 ?
69 |
70 |
76 | window.open(tag.url, '_blank')} />
82 |
:
83 | }
84 |
85 | );
86 | }
87 | }
88 |
89 | const ShowLoading = ({project}) => {
90 | return (project !== "" && );
91 | }
92 |
93 | const mapStateToProps = (state) => {
94 | return {
95 | wcProjectNames: state.wordCloudReducer.data,
96 | isSelectLoading: state.wordCloudReducer.isLoading,
97 | wcSavedProjects: Object.keys(state.wordCloudReducer.wcSavedData),
98 | wcShowResults: state.wordCloudReducer.wcShowData,
99 | wcIsLoading: state.wordCloudReducer.wcIsLoading
100 | }
101 | }
102 |
103 | const mapDispatchToProps = (dispatch) => {
104 | return {
105 | fetchWCProjectNames: () => dispatch(fetchWCProjectNames()),
106 | fetchWCSingleProjectVariables: (project) => dispatch(fetchWCSingleProjectVariables(project)),
107 | wcSimpleFilter: (selectedProject, filter) => dispatch(wcSimpleFilter(selectedProject, filter)),
108 | clearShowResultsTree: () => dispatch(clearShowResultsTree())
109 | }
110 | }
111 | export default connect(mapStateToProps, mapDispatchToProps)(WordCloudRender);
112 |
--------------------------------------------------------------------------------
/src/css/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | background:#efefef;
3 | height:100%;
4 | margin:25px;
5 | padding:45px;
6 | }
7 |
8 | .App-title {
9 | font-size:40px;
10 | background: white;
11 | padding: 20px;
12 | margin-bottom: 30px;
13 | border-style: solid;
14 | border-color: #313131;
15 | text-align: center;
16 | }
17 |
18 | .App-intro {
19 | font-size: large;
20 | }
21 |
22 | .App-note {
23 | color: #ED4337;
24 | margin-left:40px;
25 | }
26 |
--------------------------------------------------------------------------------
/src/css/Home.css:
--------------------------------------------------------------------------------
1 | #home {
2 | margin: 30px;
3 | text-align: justify;
4 | }
5 |
--------------------------------------------------------------------------------
/src/css/Results.css:
--------------------------------------------------------------------------------
1 | .Results {
2 | width: 30%;
3 | margin-left: 40px;
4 | }
5 |
6 | .filter-word {
7 | /*margin-bottom: 5px;*/
8 | }
9 |
10 | #variable-results {
11 | margin-top: 20px;
12 | }
13 |
--------------------------------------------------------------------------------
/src/css/Search.css:
--------------------------------------------------------------------------------
1 | .checkbox-grid li {
2 | display: block;
3 | float: left;
4 | width: 50%;
5 | /*border-style: dotted;*/
6 | }
7 |
8 | .checkbox-grid {
9 | margin-bottom: 15px;
10 | }
11 |
12 | .loading-symbol {
13 | margin: 50px 0px 0px 25px;
14 | }
15 |
16 | #checkBox-submit {
17 | /*background-color: grey;*/
18 | margin-top: 10px;
19 | }
20 |
--------------------------------------------------------------------------------
/src/css/WordCloudRender.css:
--------------------------------------------------------------------------------
1 | .project-select {
2 | width: 50%;
3 | margin: 10px 5px 5px 0px;
4 | }
5 |
6 | #word-cloud-note {
7 | margin-top: 10px;
8 | }
9 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: grey;
3 | margin: 0;
4 | padding: 0;
5 | font-family: Gill Sans MT;
6 | }
7 |
8 | footer {
9 | width: 100%;
10 | height: 25px;
11 | position: fixed;
12 | bottom: 0px;
13 | color: white;
14 | background-color: #313131;
15 | text-align: center
16 | }
17 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import App from './components/App';
2 | import store from "./store";
3 | import './css/index.css';
4 |
5 | import React from 'react';
6 | import ReactDOM from 'react-dom';
7 | import { Provider } from "react-redux";
8 | import 'react-mdl/extra/material.css';
9 | import 'react-mdl/extra/material.js';
10 |
11 | const app = document.getElementById('root');
12 | ReactDOM.render(
13 |
14 | , app);
15 |
--------------------------------------------------------------------------------
/src/reducers/fetchProjNamesReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | projectNames: [],
3 | projectNamesIsLoading: false,
4 | fetchProjectNameHasError: false
5 | }
6 |
7 | export default function reducer(state=initState, action) {
8 | switch(action.type) {
9 | case "FETCH_PROJECT_NAMES_PENDING": {
10 | return {...state, projectNamesIsLoading: true};
11 | }
12 | case "FETCH_PROJECT_NAMES_REJECTED": {
13 | return {...state, projectNamesIsLoading: false, fetchProjectNameHasError: true};
14 | }
15 | case "FETCH_PROJECT_NAMES_FULFILLED": {
16 | return {...state, projectNamesIsLoading: false, projectNames: action.payload.data};
17 | }
18 | default: {
19 | return state;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/reducers/fetchProjVarReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | results: {},
3 | filteredResults: {},
4 | isLoading: false,
5 | hasError: false
6 | }
7 |
8 | export default function reducer(state=initState, action) {
9 | switch(action.type) {
10 | case "FETCH_PROJECT_VARIABLES_PENDING": {
11 | return {...state, isLoading: true};
12 | }
13 | case "FETCH_PROJECT_VARIABLES_REJECTED": {
14 | return {...state, isLoading: false, hasError: true};
15 | }
16 | case "FETCH_PROJECT_VARIABLES_FULFILLED": {
17 | return {...state, isLoading: false, filteredResults: action.filtered, results: action.results};
18 | }
19 | default: {
20 | return state;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux";
2 | import fetchProjNamesReducer from "./fetchProjNamesReducer";
3 | import fetchProjVarReducer from "./fetchProjVarReducer";
4 | import wordCloudReducer from "./wordCloudReducer";
5 |
6 | export default combineReducers({
7 | fetchProjNamesReducer,
8 | fetchProjVarReducer,
9 | wordCloudReducer
10 | })
11 |
12 |
--------------------------------------------------------------------------------
/src/reducers/wordCloudReducer.js:
--------------------------------------------------------------------------------
1 | const initState = {
2 | data: [],
3 | isLoading: false,
4 | hasError: false,
5 | wcShowData: [],
6 | wcIsLoading: false,
7 | wcHasError: false,
8 | wcSavedData: {}
9 | }
10 |
11 | export default function reducer(state=initState, action) {
12 | switch(action.type) {
13 | case "FETCH_WC_PROJECT_NAMES_PENDING": {
14 | return {...state, isLoading: true};
15 | }
16 | case "FETCH_WC_PROJECT_NAMES_REJECTED": {
17 | return {...state, isLoading: false, hasError: true};
18 | }
19 | case "FETCH_WC_PROJECT_NAMES_FULFILLED": {
20 | return {...state, isLoading: false, data: action.payload.data};
21 | }
22 | case "FETCH_WC_PROJECT_VARIABLES_PENDING": {
23 | return {...state, wcIsLoading: true}
24 | }
25 | case "FETCH_WC_PROJECT_VARIABLES_REJECTED": {
26 | return {...state, wcIsLoading: false, wcHasError: true}
27 | }
28 | case "FETCH_WC_PROJECT_VARIABLES_FULFILLED": {
29 | return {...state, wcIsLoading: false, wcSavedData: action.savedResults, wcShowData: action.resToBeShowed}
30 | }
31 | case "CLEAR_FETCH_WC_PROJECT_VARIABLES_SHOW_RESULTS": {
32 | return {...state, wcShowData: [] }
33 | }
34 | default: {
35 | return state;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import { applyMiddleware, createStore } from "redux";
2 | import thunk from "redux-thunk";
3 | import promiseMiddleware from "redux-promise-middleware";
4 | import reducer from "./reducers";
5 |
6 | const middleware = applyMiddleware(promiseMiddleware(), thunk);
7 |
8 | export default createStore(reducer, middleware);
9 |
10 |
--------------------------------------------------------------------------------