diff --git a/.gitignore b/.gitignore index d30f40ef..604bb952 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +#personal addings +*.swp diff --git a/README.md b/README.md index d6331967..e84c875d 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,42 @@ This repo is a code-along with the first project in the [React Nanodegree progra Most of the commits in this repository correspond to videos in the program. -## Project Setup +## How to run this My Reads project locally -* clone the Project - `git@github.com:udacity/reactnd-chirper-app.git` -* install the dependencies - `npm install` +First clone the project from desired repo +To see current state: +* clone from MarinEstrada page `git@github.com:MarinEstrada/reactnd-chirper-app.git` +To see original starter state +* clone the Project from original Udacity page - `git@github.com:udacity/reactnd-chirper-app.git` + +This project runs locally on "localhost:3000/" using +* npm (Node Package Manager) +* Docker + +### Using npm +* install all project dependencies with: +`npm install` +* start the development server with: +`npm start` + +### Using Docker +To start the app locally run: +`docker-compose up -d` + +To download extra needed dependencies run: +`bash add_dependencies.sh {dependency_name}` + +To take a look at the logs: +`docker-compose logs -f` + +To tear the containers down +`docker-compose down` ## Contributing -Because this is a code-along project and the commits correspond to specific videos in the program, we will not be accepting pull requests. +Because this is a code-along project and the commits correspond to specific videos in the program, Udacity will not be accepting pull requests. -If you feel like there's a major problem, please open an issue to discuss the problem and potential resolution. +If you feel like there's a major problem, please open an issue on the Udacity repo to discuss the problem and potential resolution. ## License diff --git a/add_dependancies.sh b/add_dependancies.sh new file mode 100755 index 00000000..9dea923f --- /dev/null +++ b/add_dependancies.sh @@ -0,0 +1,27 @@ +# !/bin/bash + +# any parmeter I want to add in, use dollar sign +# eg $1 == first param, $2 == second, etc +# can name param whatever you want + +dependency=$1 +container_name="reactnd-chirper-app_app_1" + +if [ -z "$dependency" ] +then + echo "please call script with dependecy you would like to add" + echo "./add_dependancies.sh {dependecy}" +else + echo "installing $dependecy" + echo "running: yarn add $dependecy, in docker container $container_name" + docker exec $container_name yarn add $dependency +fi + + + + +#yarn add prop-types +#yarn add escape-string-regexp +#yarn add sort-by +#yarn add react-router-dom +#yarn add prop-types diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..724770e4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + image: node:12-alpine + command: sh -c "yarn install && yarn start" + #command: sh -c "yarn create react-app udacity-goals-todos && cd udacity-goals-todos && yarn add prop-types" + ports: + - 3000:3000 + working_dir: /reactnd-chirper-app + volumes: + - ./:/reactnd-chirper-app:consistent + stdin_open: true + diff --git a/package.json b/package.json index 27798f4d..d2d0d2d2 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,14 @@ "version": "0.1.0", "private": true, "dependencies": { - "react": "^16.2.0", - "react-dom": "^16.2.0", - "react-scripts": "1.1.1" + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-icons": "^4.2.0", + "react-redux": "^7.2.4", + "react-redux-loading": "^4.6.1", + "react-scripts": "1.1.1", + "redux": "^4.1.0", + "redux-thunk": "^2.3.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/actions/authedUser.js b/src/actions/authedUser.js new file mode 100644 index 00000000..39db9ade --- /dev/null +++ b/src/actions/authedUser.js @@ -0,0 +1,8 @@ +export const SET_AUTHED_USER = 'SET_AUTHED_USER' + +export function setAuthedUser(id) { + return { + type: SET_AUTHED_USER, + id, + } +} diff --git a/src/actions/shared.js b/src/actions/shared.js new file mode 100644 index 00000000..8edf3707 --- /dev/null +++ b/src/actions/shared.js @@ -0,0 +1,22 @@ +import { getInitialData } from '../utils/api' +import { receiveUsers } from './users' +import { receiveTweets } from './tweets' +import { setAuthedUser } from './authedUser' +import { showLoading, hideLoading } from 'react-redux-loading' + +//user currently 'logged in' +const AUTHED_ID = 'tylermcginnis' + +export function handleInitialData() { + //using redux thunk pattern + return (dispatch) => { + dispatch(showLoading()) + return getInitialData() + .then(({ users, tweets }) => { + dispatch(receiveUsers(users)) + dispatch(receiveTweets(tweets)) + dispatch(setAuthedUser(AUTHED_ID)) + dispatch(hideLoading()) + }) + } +} diff --git a/src/actions/tweets.js b/src/actions/tweets.js new file mode 100644 index 00000000..43311e29 --- /dev/null +++ b/src/actions/tweets.js @@ -0,0 +1,58 @@ +import { saveLikeToggle, saveTweet } from '../utils/api' +import { showLoading, hideLoading } from 'react-redux-loading' + +export const RECEIVE_TWEETS = 'RECEIVE_TWEETS' +export const TOGGLE_TWEET = 'TOGGLE_TWEET' +export const ADD_TWEET = 'ADD_TWEET' + +function addTweet(tweet) { + return { + type: ADD_TWEET, + tweet, + } +} + +export function handleAddTweet(text, replyingTo) { + return (dispatch, getState) => { + const { authedUser } = getState() + + dispatch(showLoading()) + + return saveTweet({ + text, + author: authedUser, + replyingTo + }) + .then((tweet) => dispatch(addTweet(tweet))) + .then(() => dispatch(hideLoading())) + } +} + +export function receiveTweets(tweets) { + return { + type: RECEIVE_TWEETS, + tweets, + } +} + +function toggleTweet({ id, authedUser, hasLiked }) { + return { + type: TOGGLE_TWEET, + id, + authedUser, + hasLiked, + } +} + +export function handleToggleTweet(info) { + return(dispatch) => { + dispatch(toggleTweet(info)) + + return saveLikeToggle(info) + .catch((e) => { + console.warn('Error in handleToggleTweet: ', e) + dispatch(toggleTweet(info)) + alert("Error: couldn't like tweet. Try again.") + }) + } +} diff --git a/src/actions/users.js b/src/actions/users.js new file mode 100644 index 00000000..bd00beac --- /dev/null +++ b/src/actions/users.js @@ -0,0 +1,8 @@ +export const RECEIVE_USERS = 'RECEIVE_USERS' + +export function receiveUsers(users) { + return { + type: RECEIVE_USERS, + users, + } +} diff --git a/src/components/App.js b/src/components/App.js index 4859a621..757680c0 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,13 +1,34 @@ import React, { Component } from 'react' +import { connect } from 'react-redux' +import { handleInitialData } from '../actions/shared' +import Dashboard from './Dashboard' +import LoadingBar from 'react-redux-loading' +import NewTweet from './NewTweet' +import TweetPage from './TweetPage' class App extends Component { - render() { - return ( -
- Starter Code -
- ) - } + componentDidMount() { + this.props.dispatch(handleInitialData()) + } + render() { + return ( +
+ + {this.props.loading === true + ? null + : } +
+ ) + } } -export default App \ No newline at end of file +function mapStateToProps({ authedUser }) { + return{ + loading: authedUser === null + } +} + +//We don't need anything from state, so leave +//first invocation blank +//second invocation is where we will render (eg, App) +export default connect(mapStateToProps)(App) diff --git a/src/components/Dashboard.js b/src/components/Dashboard.js new file mode 100644 index 00000000..0ba5476c --- /dev/null +++ b/src/components/Dashboard.js @@ -0,0 +1,31 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' +import Tweet from './Tweet' + +class Dashboard extends Component { + render() { + return( +
+

Your Timeline

+ +
+ ) + } +} + +//takes in state of store, +//specifically only portion it needs (tweets) +function mapStateToProps ({ tweets }) { + return{ + tweetIds: Object.keys(tweets) + .sort((a,b) => tweets[b].timestamp - tweets[a].timestamp) + } +} + +export default connect(mapStateToProps)(Dashboard) diff --git a/src/components/NewTweet.js b/src/components/NewTweet.js new file mode 100644 index 00000000..3dad2201 --- /dev/null +++ b/src/components/NewTweet.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' +import { handleAddTweet } from '../actions/tweets' + +class NewTweet extends Component { + state = { + text: '', + } + + handleChange = (e) => { + const text = e.target.value + + this.setState(() => ({ text })) + } + + handleSubmit = (e) => { + e.preventDefault() + + const { text } = this.state + const { dispatch, id } = this.props + + dispatch(handleAddTweet(text, id)) + + this.setState(() => ({ text: '' })) + + } + + render() { + + const { text } = this.state + + {/* todo: Redirect to '/' if submited */} + + const charsLeft = 280 - text.length + + return( +
+

Compose New Tweet

+
+