diff --git a/package.json b/package.json index d0ee9436..b0fadbce 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,21 @@ "version": "0.1.0", "private": true, "dependencies": { - "@testing-library/jest-dom": "^5.11.4", - "@testing-library/react": "^11.1.0", - "@testing-library/user-event": "^12.1.10", + "@testing-library/jest-dom": "^5.16.2", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^13.5.0", + "firebase": "^8.6.1", + "firebase-tools": "^9.11.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-player": "^2.9.0", + "react-redux": "^7.2.4", "react-router-dom": "^5.2.0", - "react-scripts": "4.0.3", - "styled-components": "^5.2.3", - "web-vitals": "^1.0.1" + "react-scripts": "^4.0.3", + "redux": "^4.1.0", + "redux-thunk": "^2.3.0", + "styled-components": "^5.3.0", + "web-vitals": "^1.1.2" }, "scripts": { "start": "react-scripts start", diff --git a/public/images/article-icon.png b/public/images/article-icon.png new file mode 100644 index 00000000..863e34df Binary files /dev/null and b/public/images/article-icon.png differ diff --git a/public/images/clap-icon.png b/public/images/clap-icon.png new file mode 100644 index 00000000..d3effaf5 Binary files /dev/null and b/public/images/clap-icon.png differ diff --git a/public/images/close-icon.png b/public/images/close-icon.png new file mode 100644 index 00000000..951bf63f Binary files /dev/null and b/public/images/close-icon.png differ diff --git a/public/images/comment-icon.png b/public/images/comment-icon.png new file mode 100644 index 00000000..66ce61ba Binary files /dev/null and b/public/images/comment-icon.png differ diff --git a/public/images/ellipsis.png b/public/images/ellipsis.png new file mode 100644 index 00000000..2abd4e59 Binary files /dev/null and b/public/images/ellipsis.png differ diff --git a/public/images/event-icon.png b/public/images/event-icon.png new file mode 100644 index 00000000..8db3ff53 Binary files /dev/null and b/public/images/event-icon.png differ diff --git a/public/images/like-icon.png b/public/images/like-icon.png new file mode 100644 index 00000000..d27a55e0 Binary files /dev/null and b/public/images/like-icon.png differ diff --git a/public/images/linkedin.png b/public/images/linkedin.png index 496733dd..743d3e62 100644 Binary files a/public/images/linkedin.png and b/public/images/linkedin.png differ diff --git a/public/images/photo-icon.png b/public/images/photo-icon.png new file mode 100644 index 00000000..237f3f82 Binary files /dev/null and b/public/images/photo-icon.png differ diff --git a/public/images/shared-comment.png b/public/images/shared-comment.png new file mode 100644 index 00000000..6add17d3 Binary files /dev/null and b/public/images/shared-comment.png differ diff --git a/public/images/shared-img.png b/public/images/shared-img.png new file mode 100644 index 00000000..ade17228 Binary files /dev/null and b/public/images/shared-img.png differ diff --git a/public/images/shared-vid.png b/public/images/shared-vid.png new file mode 100644 index 00000000..ede42953 Binary files /dev/null and b/public/images/shared-vid.png differ diff --git a/public/images/spin-loading.gif b/public/images/spin-loading.gif new file mode 100644 index 00000000..941ee559 Binary files /dev/null and b/public/images/spin-loading.gif differ diff --git a/public/images/video-icon.png b/public/images/video-icon.png new file mode 100644 index 00000000..91ad70cc Binary files /dev/null and b/public/images/video-icon.png differ diff --git a/src/App.css b/src/App.css index e69de29b..d5d655fd 100644 --- a/src/App.css +++ b/src/App.css @@ -0,0 +1,3 @@ +* { + scroll-behavior: smooth; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 3058f6f3..068ba716 100644 --- a/src/App.js +++ b/src/App.js @@ -1,10 +1,17 @@ -import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; -import "./App.css"; -import Header from "./components/Header"; -import Home from "./components/Home"; -import Login from "./components/Login"; +import { connect } from 'react-redux'; +import { useEffect } from 'react'; +import { BrowserRouter as Router, Switch, Route} from 'react-router-dom'; +import './App.css'; +import Login from './components/Login'; +import Home from './components/Home'; +import Header from './components/Header'; +import { getUserAuth } from './actions'; + +function App(props) { +useEffect(() => { + props.getUserAuth(); +}, []); -function App() { return (
@@ -22,4 +29,12 @@ function App() { ); } -export default App; +const mapStateToProps = (state) => { + return {}; +}; + +const mapDispatchToProps = (dispatch) => ({ + getUserAuth: () => dispatch(getUserAuth()), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(App); \ No newline at end of file diff --git a/src/actions/actionType.js b/src/actions/actionType.js new file mode 100644 index 00000000..0b9f5804 --- /dev/null +++ b/src/actions/actionType.js @@ -0,0 +1,3 @@ +export const SET_USER = "SET_USER"; +export const SET_LOADING_STATUS = "SET_LOADING_STATUS"; +export const GET_ARTICLES = "GET_ARTICLES"; \ No newline at end of file diff --git a/src/actions/index.js b/src/actions/index.js new file mode 100644 index 00000000..54cd9ebf --- /dev/null +++ b/src/actions/index.js @@ -0,0 +1,117 @@ +import { auth, provider, storage } from '../firebase'; +import db from '../firebase'; +import { SET_USER, SET_LOADING_STATUS, GET_ARTICLES } from './actionType'; + +export const setUser = (payload) => ({ + type: SET_USER, + user: payload, +}) + +export const setLoading = (status) => ({ + type: SET_LOADING_STATUS, + status : status, +}) + +export const getArticles = (payload) => ({ + type: GET_ARTICLES, + payload: payload, +}) + +export function signInAPI() { + return (dispatch) => { + auth + .signInWithPopup(provider) + .then((payload) => { + dispatch(setUser(payload.user)); + }) + .catch((error) => alert(error.message)); + }; +} + +export function getUserAuth() { + return (dispatch) => { + auth.onAuthStateChanged(async (user) => { + if(user) { + dispatch(setUser(user)); + } + }) + } +} + +export function signOutAPI() { + return(dispatch) => { + auth + .signOut() + .then(() => { + dispatch(setUser(null)); + }) + .catch((error) => { + console.log(error.message); + }); + }; +} + +export function postArticleAPI(payload) { + return (dispatch) => { + dispatch(setLoading(true)); + + if(payload.image != '') { + const upload = storage + .ref(`images/${payload.image.name}`) + .put(payload.image); + upload.on('state-changed', (snapshot) => { + const progress = + (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + + console.log(`Progress: ${progress}%`); + if(snapshot.state === 'RUNNING') { + console.log(`Progress: ${progress}%`); + } + }, error => console.log(error.code), + async () => { + const downloadURL = await upload.snapshot.ref.getDownloadURL(); + db.collection("articles").add({ + actor: { + description: payload.user.email, + title: payload.user.displayName, + date: payload.timestamp, + image: payload.user.photoURL + }, + video: payload.video, + sharedImg: downloadURL, + comments: 0, + description: payload.description, + }); + dispatch(setLoading(false)); + }); + } + else if(payload.video) { + db.collection('articles').add({ + actor: { + description: payload.user.email, + title: payload.user.displayName, + date: payload.timestamp, + image: payload.user.photoURL, + }, + video: payload.video, + sharedImg: '', + comments: 0, + description: payload.description, + }); + dispatch(setLoading(false)); + } +}; +} + +export function getArticlesAPI() { + return (dispatch) => { + let payload; + + db.collection('articles') + .orderBy("actor.date", "desc") + .onSnapshot((snapshot) => { + payload = snapshot.docs.map((doc) => doc.data()); + dispatch(getArticles(payload)); + }); + }; +} \ No newline at end of file diff --git a/src/components/Header.js b/src/components/Header.js index 1cfcb32f..4b78ee34 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,260 +1,288 @@ -import styled from "styled-components"; +import styled from 'styled-components'; +import { connect } from 'react-redux'; +import { signOutAPI } from '../actions'; const Header = (props) => { - return ( - - - - - - - - -
- -
- - - -
- +
+
+ ); +} const Container = styled.div` - background-color: white; - border-bottom: 1px solid rgba(0, 0, 0, 0.08); - left: 0; - padding: 0 24px; - position: fixed; - top: 0; - width: 100vw; - z-index: 100; + background-color: #ffffff; + border-bottom: 1px solid rgba(0,0,0,0.08); + left: 0; + padding: 0 24px; + top: 0; + position: fixed; + width: 100vw; + z-index: 100; `; const Content = styled.div` - display: flex; - align-items: center; - margin: 0 auto; - min-height: 100%; - max-width: 1128px; + display: flex; + align-items: center; + margin: 0 auto; + min-height: 100%; + max-width: 1128px; `; const Logo = styled.span` - margin-right: 8px; - font-size: 0px; + margin-right: 8px; + font-size: 0px; `; const Search = styled.div` - opacity: 1; - flex-grow: 1; - position: relative; - & > div { - max-width: 280px; - input { - border: none; - box-shadow: none; - background-color: #eef3f8; - border-radius: 2px; - color: rgba(0, 0, 0, 0.9); - width: 218px; - padding: 0 8px 0 40px; - line-height: 1.75; - font-weight: 400; - font-size: 14px; - height: 34px; - border-color: #dce6f1; - vertical-align: text-top; + opacity: 1; + flex-grow: 1; + position: relative; + + & > div { + max-width: 280px; + + input { + border: none; + box-shadow: none; + background-color: #eef3f8; + border-radius: 2px; + color: rgba(0,0,0,0.9); + width: 218px; + padding: 0 8px 0 40px; + line-height: 1.75; + font-weight: 400; + font-size: 14px; + height: 34px; + border-color: #dce6f1; + vertical-align: text-top; + } } - } `; const SearchIcon = styled.div` - width: 40px; - position: absolute; - z-index: 1; - top: 10px; - left: 2px; - border-radius: 0 2px 2px 0; - margin: 0; - pointer-events: none; - display: flex; - justify-content: center; - align-items: center; + width: 40px; + position: absolute; + z-index: 1; + top: 10px; + left: 2px; + border-radius: 0 2px 2px 0; + margin: 0; + pointer-events: none; + display: flex; + justify-content: center; + align-items: center; `; const Nav = styled.nav` - margin-left: auto; - display: block; - @media (max-width: 768px) { - position: fixed; - left: 0; - bottom: 0; - background: white; - width: 100%; - } + margin-left: auto; + display: block; + + @media (max-width: 768px) { + position: fixed; + left: 0; + bottom: 0; + background: #ffffff; + width: 100%; + } `; const NavListWrap = styled.ul` - display: flex; - flex-wrap: nowrap; - list-style-type: none; + display: flex; + flex-wrap: nowrap; + list-style-type: none; - .active { - span:after { - content: ""; - transform: scaleX(1); - border-bottom: 2px solid var(--white, #fff); - bottom: 0; - left: 0; - position: absolute; - transition: transform 0.2s ease-in-out; - width: 100%; - border-color: rgba(0, 0, 0, 0.9); + .active { + span:after { + content: ''; + transform: scaleX(1); + border-bottom: 2px solid var(--white, #ffffff); + bottom: 0; + left: 0; + position: absolute; + transition: transform 0.2s ease-in-out; + width: 100%; + border-color: rgba(0,0,0,0.9); + } } - } `; const NavList = styled.li` - display: flex; - align-items: center; - a { - align-items: center; - background: transparent; display: flex; - flex-direction: column; - font-size: 12px; - font-weight: 400; - justify-content: center; - line-height: 1.5; - min-height: 52px; - min-width: 80px; - position: relative; - text-decoration: none; + align-items: center; - span { - color: rgba(0, 0, 0, 0.6); - display: flex; - align-items: center; - } + a { + align-items: center; + background: transparent; + display: flex; + flex-direction: column; + font-size: 12px; + font-weight: 400; + justify-content: center; + line-height: 1.5; + min-height: 42px; + min-width: 88px; + position: relative; + text-decoration: none; - @media (max-width: 768px) { - min-width: 70px; + span { + color: rgba(0,0,0,0.6); + display: flex; + align-items: center; + } + + @media (max-width: 768px) { + min-width: 70px; + } } - } - &:hover, - &:active { - a { - span { - color: rgba(0, 0, 0, 0.9); - } + &:hover,&:active { + a { + span { + color: rgba(0, 0, 0, 0.9); + } + } } - } `; const SignOut = styled.div` - position: absolute; - top: 45px; - background: white; - border-radius: 0 0 5px 5px; - width: 100px; - height: 40px; - font-size: 16px; - transition-duration: 167ms; - text-align: center; - display: none; + cursor: pointer; + position: absolute; + top: 45px; + background: #ffffff; + border-radius: 0 0 5px 5px; + width: 100px; + box-shadow: 2px 3px 5px -2px rgba(110,104,104,0.75); + height: 40px; + font-size: 16px; + transition-duration: 167ms; + text-align: center; + display: none; `; const User = styled(NavList)` - a > svg { - width: 24px; - border-radius: 50%; - } + a > svg { + padding-top: 5px; + width: 24px; + height: 24px; + border-radius: 50%; + } - a > img { - width: 24px; - height: 24px; - border-radius: 50%; - } + a > img { + width: 24px; + height: 24px; + padding-top: 5px; + border-radius: 50%; + } - span { - display: flex; - align-items: center; - } + span { + display: flex; + align-items: center; + cursor: pointer; + } - &:hover { - ${SignOut} { - align-items: center; - display: flex; - justify-content: center; + &:hover { + ${SignOut} { + align-items: center; + display: flex; + justify-content: center; + } } - } `; const Work = styled(User)` - border-left: 1px solid rgba(0, 0, 0, 0.08); + border-left: 1px solid rgba(0, 0, 0, 0.08); `; -export default Header; +const mapStateToProps = (state) => { + return { + user: state.userState.user, + }; +}; + +const mapDispatchToProps = (dispatch) => ({ + signOut: () => dispatch(signOutAPI()), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Header); \ No newline at end of file diff --git a/src/components/Home.js b/src/components/Home.js index db0c42ad..31aafd47 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -1,81 +1,91 @@ import styled from "styled-components"; -import Leftside from "./Leftside"; -import Main from "./Main"; -import Rightside from "./Rightside"; - +import Leftside from './Leftside'; +import Main from './Main'; +import Rightside from './Rightside'; +import { Redirect } from 'react-router-dom'; +import { connect } from 'react-redux'; + const Home = (props) => { - return ( - -
-
- Hiring in a hurry? - -
-

- Find talented pros in record time with Upwork and keep business - moving. -

-
- - -
- - - - ); -}; + return ( + + {!props.user && } +
+
+ Hiring in a hurry? - +
+

Find talents in record time with LinkedIn Premium and unlock special benefits!

+
+ + + +
+ + + + ); +} const Container = styled.div` - padding-top: 52px; - max-width: 100%; + padding-top: 52px; + max-width: 100%; `; const Content = styled.div` - max-width: 1128px; - margin-left: auto; - margin-right: auto; + max-width: 1120px; + margin-left: auto; + margin-right: auto; `; const Section = styled.section` - min-height: 50px; - padding: 16px 0; - box-sizing: content-box; - text-align: center; - text-decoration: underline; - display: flex; - justify-content: center; - h5 { - color: #0a66c2; - font-size: 14px; - a { - font-weight: 700; + min-height: 50px; + padding: 16px 0; + box-sizing: content-box; + text-align: center; + text-decoration: underline; + display: flex; + justify-content: center; + + h5 { + color: #0a66c2; + font-size: 14px; + + a { + font-weight: 700; + } } - } - p { - font-size: 14px; - color: #434649; - font-weight: 600; - } + p { + font-size: 14px; + color: #434649; + font-weight: 600; + } - @media (max-width: 768px) { - flex-direction: column; - padding: 0 5px; - } + @media (max-width: 768px) { + flex-direction: column; + padding: 0 5px; + } `; const Layout = styled.div` - display: grid; - grid-template-areas: "leftside main rightside"; - grid-template-columns: minmax(0, 5fr) minmax(0, 12fr) minmax(300px, 7fr); - column-gap: 25px; - row-gap: 25px; - /* grid-template-row: auto; */ - margin: 25px 0; - @media (max-width: 768px) { - display: flex; - flex-direction: column; - padding: 0 5px; - } + display: grid; + grid-template-areas: "leftside main rightside"; + grid-template-columns: minmax(0,5fr) minmax(0,12fr) minmax(300px,7fr); + column-gap: 25px; + row-gap: 25px; + margin: 25px 0; + /*grid-template-row: auto;*/ + + @media (max-width: 768px) { + display: flex; + flex-direction: column; + padding: 0 5px; + } `; -export default Home; +const mapStateToProps = (state) => { + return { + user: state.userState.user, + }; +}; + +export default connect(mapStateToProps)(Home); \ No newline at end of file diff --git a/src/components/Leftside.js b/src/components/Leftside.js index b447259a..5516acb2 100644 --- a/src/components/Leftside.js +++ b/src/components/Leftside.js @@ -1,208 +1,225 @@ -import styled from "styled-components"; +import styled from 'styled-components'; +import { connect } from 'react-redux'; const Leftside = (props) => { - return ( - - - - - - - Welcome, there! - - - Add a photo - - - - -
- Connections - Grow your network -
- -
-
- - - - My Items - - -
- - - - Groups - - - - Events - - - - - Follow Hashtags - - - Discover more - - -
- ); + return ( + + + + + + + + Welcome, {props.user ? props.user.displayName : "there"}! + + + + + + + + + +
+ Connections + Grow your network +
+ +
+
+ + + + + My Items + + +
+ + + + Groups + + + + Events + + + + + Follow Hashtags + + + Discover more + + +
+ ); }; const Container = styled.div` - grid-area: leftside; + grid-area: leftside; `; const ArtCard = styled.div` - text-align: center; - overflow: hidden; - margin-bottom: 8px; - background-color: #fff; - border-radius: 5px; - transition: box-shadow 83ms; - position: relative; - border: none; - box-shadow: 0 0 0 1px rgb(0 0 0 / 15%), 0 0 0 rgb(0 0 0 / 20%); + text-align: center; + overflow: hidden; + margin-bottom: 8px; + background-color: #ffffff; + border-radius: 5px; + transition: box-shadow 83ms; + position: relative; + border: none; + box-shadow: 0 0 0 1px rgb(0 0 0 / 15%), 0 0 0 rgb(0 0 0 / 20%); `; const UserInfo = styled.div` - border-bottom: 1px solid rgba(0, 0, 0, 0.15); - padding: 12px 12px 16px; - word-wrap: break-word; - word-break: break-word; + border-bottom: 1px solid rgba(0,0,0,0.15); + padding: 12px 12px 16px; + word-wrap: break-word; + word-break: break-word; `; const CardBackground = styled.div` - background: url("/images/card-bg.svg"); - background-position: center; - background-size: 462px; - height: 54px; - margin: -12px -12px 0; + background: url('/images/card-bg.svg'); + background-position: center; + background-size: 462px; + height: 54px; + margin: -12px -12px 0; `; const Photo = styled.div` - box-shadow: none; - background-image: url("/images/photo.svg"); - width: 72px; - height: 72px; - box-sizing: border-box; - background-clip: content-box; - background-color: white; - background-position: center; - background-size: 60%; - background-repeat: no-repeat; - border: 2px solid white; - margin: -38px auto 12px; - border-radius: 50%; + box-shadow: none; + background-image: url('/images/photo.svg'); + width: 72px; + height: 72px; + box-sizing: border-box; + background-clip: content-box; + background-color: #ffffff; + background-position: center; + background-size: 60%; + background-repeat: no-repeat; + border: 2px solid #ffffff; + margin : -38px auto 12px; + border-radius: 50%; `; const Link = styled.div` - font-size: 16px; - line-height: 1.5; - color: rgba(0, 0, 0, 0.9); - font-weight: 600; + font-size: 16px; + line-height: 16px; + color: rgba(0,0,0,0.9); + font-weight: 600; `; const AddPhotoText = styled.div` - color: #0a66c2; - margin-top: 4px; - font-size: 12px; - line-height: 1.33; - font-weight: 400; + color: #0a66c2; + margin-top: 4px; + font-size: 12px; + line-height: 1.33; + font-weight: 400; `; const Widget = styled.div` - border-bottom: 1px solid rgba(0, 0, 0, 0.15); - padding-top: 12px; - padding-bottom: 12px; + border-bottom: 1px solid rgba(0,0,0,0.15); + padding-top: 12px; + padding-bottom: 12px; + + & > a { + text-decoration: none; + display: flex; + justify-content: space-between; + align-items: center; + padding: 4px 12px; + + &:hover { + background-color: rgba(0,0,0,0.08); + } - & > a { - text-decoration: none; - display: flex; - justify-content: space-between; - align-items: center; - padding: 4px 12px; + div { + display: flex; + flex-direction: column; + text-align: left; - &:hover { - background-color: rgba(0, 0, 0, 0.08); - } + span { + font-size: 12px; + line-height: 1.333; - div { - display: flex; - flex-direction: column; - text-align: left; - span { - font-size: 12px; - line-height: 1.333; - &:first-child { - color: rgba(0, 0, 0, 0.6); - } - &:nth-child(2) { - color: rgba(0, 0, 0, 1); + &:first-child { + color: rgba(0, 0, 0, 0.6); + } + + &:nth-child(2) { + color: rgba(0, 0, 0, 1); + } + } } - } } - } - svg { - color: rgba(0, 0, 0, 1); - } + svg { + color: rgba(0, 0, 0, 1); + } `; const Item = styled.a` - border-color: rgba(0, 0, 0, 0.8); - text-align: left; - padding: 12px; - font-size: 12px; - display: block; - span { - display: flex; - align-items: center; - color: rgba(0, 0, 0, 1); - svg { - color: rgba(0, 0, 0, 0.6); + border-color: rgba(0, 0, 0, 0.8); + text-align: left; + padding: 12px; + font-size: 12px; + display: block; + + span { + display: flex; + align-items: center; + color: rgba(0, 0, 0, 1); + + svg { + color: rgba(0, 0, 0, 0.6); + } } - } - &:hover { - background-color: rgba(0, 0, 0, 0.08); - } + &:hover { + background-color: rgba(0, 0, 0, 0.08); + } `; const CommunityCard = styled(ArtCard)` - padding: 8px 0 0; - text-align: left; - display: flex; - flex-direction: column; - a { - color: black; - padding: 4px 12px 4px 12px; - font-size: 12px; + padding: 8px 0 0; + text-align: left; + display: flex; + flex-direction: column; - &:hover { - color: #0a66c2; - } + a { + color: #000000; + padding: 4px 12px; + font-size: 12px; - span { - display: flex; - align-items: center; - justify-content: space-between; - } + &:hover { + color: #0a66c2; + } - &:last-child { - color: rgba(0, 0, 0, 0.6); - text-decoration: none; + span { + display: flex; + align-items: center; + justify-content: space-between; + } - border-top: 1px solid #d6cec2; - padding: 12px; - &:hover { - background-color: rgba(0, 0, 0, 0.08); - } + &:last-child { + color: rgba(0,0,0,0.6); + text-decoration: none; + border-top: 1px solid #d6cec2; + padding: 12px; + + &:hover { + background-color: rgba(0,0,0,0.08); + } + } } - } `; -export default Leftside; +const mapStateToProps = (state) => { + return { + user: state.userState.user, + }; +}; + +export default connect(mapStateToProps)(Leftside); \ No newline at end of file diff --git a/src/components/Login.js b/src/components/Login.js index 10bf7e8b..b93a4f92 100644 --- a/src/components/Login.js +++ b/src/components/Login.js @@ -1,169 +1,196 @@ import styled from "styled-components"; +import { connect } from 'react-redux'; +import { signInAPI } from '../actions'; +import { Redirect } from 'react-router'; const Login = (props) => { - return ( - - -
- -

Welcome to your professional community

- -
-
- - - Sign in with Google - -
-
-
- ); + return ( + + { + props.user && + + } + + +
+ +

Welcome to your professional community

+ +
+ +
+ props.signIn()}> + Sign in with Google + +
+
+
+ ); }; const Container = styled.div` - padding: 0px; + padding: 0px; `; const Nav = styled.nav` - max-width: 1128px; - margin: auto; - padding: 12px 0 16px; - display: flex; - align-items: center; - position: relative; - justify-content: space-between; - flex-wrap: nowrap; - - & > a { - width: 135px; - height: 34px; - @media (max-width: 768px) { - padding: 0 5px; + max-width: 1128px; + margin: auto; + padding: 12px 0 16px 0; + display: flex; + align-items: center; + position: relative; + justify-content: space-between; + flex-wrap: nowrap; + + & > a { + width: 135px; + height: 34px; + + @media (max-width: 768px) { + padding: 0 5px; + } } - } `; const Join = styled.a` - font-size: 16px; - padding: 10px 12px; - text-decoration: none; - border-radius: 4px; - color: rgba(0, 0, 0, 0.6); - margin-right: 12px; - &:hover { - background-color: rgba(0, 0, 0, 0.08); - color: rgba(0, 0, 0, 0.9); + font-size: 16px; + padding: 10px 12px; text-decoration: none; - } + color: rgba(0, 0, 0, 0.6); + margin-right: 12px; + font-weight: 600; + border-radius: 4px; + + &:hover { + background-color: rgba(0, 0, 0, 0.08); + color: rgba(0, 0, 0, 0.9); + text-decoration: none; + cursor: pointer; + } `; const SignIn = styled.a` - box-shadow: inset 0 0 0 1px #0a66c2; - color: #0a66c2; - border-radius: 24px; - transition-duration: 167ms; - font-size: 16px; - font-weight: 600; - line-height: 40px; - padding: 10px 24px; - text-align: center; - background-color: rgba(0, 0, 0, 0); - &:hover { - background-color: rgba(112, 181, 249, 0.15); + box-shadow: inset 0 0 0 1px #0a66c2; color: #0a66c2; - text-decoration: none; - } + border-radius: 24px; + transition-duration: 167ms; + font-size: 16px; + font-weight: 600; + line-height: 40px; + padding: 12px 23px; + text-align: center; + background-color: rgba(0, 0, 0, 0); + + &:hover { + background-color: rgba(112, 181, 249, 0.15); + color: #0a66c2; + text-decoration: none; + cursor: pointer; + box-shadow: inset 0 0 0 2px #0a66c2; + } `; const Section = styled.section` - display: flex; - align-content: start; - min-height: 700px; - padding-bottom: 138px; - padding-top: 40px; - padding: 60px 0; - position: relative; - flex-wrap: wrap; - width: 100%; - max-width: 1128px; - align-items: center; - margin: auto; - - @media (max-width: 768px) { + display: flex; + align-content: start; + min-height: 700px; + padding-bottom: 138px; + padding-top: 40px; + padding: 60px 0; + position: relative; + flex-wrap: wrap; + width: 100%; + align-items: center; margin: auto; - min-height: 0px; - } + + @media (max-width: 768px) { + margin: auto; + min-height: 0px; + } `; const Hero = styled.div` - width: 100%; - h1 { - padding-bottom: 0; - width: 55%; - font-size: 56px; - color: #2977c9; - font-weight: 200; - line-height: 70px; - @media (max-width: 768px) { - text-align: center; - font-size: 20px; - width: 100%; - line-height: 2; + width: 100%; + h1 { + padding-bottom: 0; + width: 55%; + font-size: 53px; + color: #2977c9; + font-weight: 200; + line-height: 70px; + + @media (max-width: 768px) { + text-align: center; + font-size: 20px; + width: 100%; + width: 100%; + line-height: 2; + } } - } - - img { - /* z-index: -1; */ - width: 700px; - height: 670px; - position: absolute; - bottom: -2px; - right: -150px; - @media (max-width: 768px) { - top: 230px; - width: initial; - position: initial; - height: initial; + + img { + /*z-index: -1;*/ + width: 700px; + height: 670px; + position: absolute; + bottom: -2px; + right: -150px; + + @media (max-width: 768px) { + top: 230px; + width: initial; + position: initial; + height: initial; + } } - } `; const Form = styled.div` - margin-top: 100px; - width: 408px; - @media (max-width: 768px) { - margin-top: 20px; - } + margin-top: 100px; + width: 408px; + @media (max-width: 768px) { + margin-top: 20px; + } `; const Google = styled.button` - display: flex; - justify-content: center; - background-color: #fff; - align-items: center; - height: 56px; - width: 100%; - border-radius: 28px; - box-shadow: inset 0 0 0 1px rgb(0 0 0 / 60%), - inset 0 0 0 2px rgb(0 0 0 / 0%) inset 0 0 0 1px rgb(0 0 0 / 0); - - vertical-align: middle; - z-index: 0; - transition-duration: 167ms; - font-size: 20px; - color: rgba(0, 0, 0, 0.6); - &:hover { - background-color: rgba(207, 207, 207, 0.25); - color: rgba(0, 0, 0, 0.75); - } + display: flex; + justify-content: center; + background-color: #fff; + align-items: center; + height: 56px; + width: 100%; + border-radius: 28px; + box-shadow: inset 0 0 0 1px rgba(0 0 0 / 60%), inset 0 0 0 2px rgb(0 0 0 / 0%) inset 0 0 0 1px rgb(0 0 0 / 0%); + vertical-align: middle; + z-index: 0; + transition-duration: 167ms; + font-size: 20px; + color: rgba(0, 0 , 0, 0.6); + + &:hover { + background-color: rgba(207, 207, 207, 0.25); + color: rgba(0, 0, 0, 0.75); + cursor: pointer; + } `; -export default Login; +const mapStateToProps = (state) => { + return { + user: state.userState.user, + }; +}; + +const mapDispatchToProps = (dispatch) => ({ + signIn: () => dispatch(signInAPI()), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Login); \ No newline at end of file diff --git a/src/components/Main.js b/src/components/Main.js index fd6e2d54..555a10e2 100644 --- a/src/components/Main.js +++ b/src/components/Main.js @@ -1,11 +1,406 @@ -import styled from "styled-components"; +import { useEffect, useState } from 'react'; +import styled from 'styled-components'; +import PostModal from './PostModal'; +import ReactPlayer from 'react-player'; +import { connect } from 'react-redux'; +import { getArticlesAPI } from '../actions'; const Main = (props) => { - return Main; + const [showModal, setShowModal] = useState("close"); + + useEffect(() => { + props.getArticles() + }, []); + + const handleClick = (e) => { + e.preventDefault(); + if(e.target !== e.currentTarget) { + return; + } + + switch(showModal) { + case "open": + setShowModal("close"); + break; + case "close": + setShowModal("open"); + break; + default: + setShowModal("close"); + break; + } + } + + return ( + // <> + // { props.articles.length === 0 ? ( + //

No articles to show.

+ // ) : + // ( + + +
+ { props.user && props.user.photoURL ? + () + : + () + } + +
+ +
+ + + + + + + +
+
+ + + { + props.loading && + } + { + props.articles.length != 0 && + props.articles.map((article, key) => ( + + + )) + } + + + +
+ // ) + // } + // + ); }; const Container = styled.div` - grid-area: main; + grid-area: main; `; -export default Main; +const CommonCard = styled.div` + text-align: center; + overflow: hidden; + margin-bottom: 8px; + background-color: #fff; + border-radius: 5px; + position: relative; + border: none; + border-radius: 0 0 0 1px rgb(0 0 0 / 15%), 0 0 0 rgb(0 0 0 / 20%); +`; + +const ShareBox = styled(CommonCard)` + display: flex; + flex-direction: column; + color: #958b7b; + margin: 0 0 8px 0; + background: #fff; + + div { + button { + outline: none; + color: rgba(0,0,0,0.6); + font-size: 14px; + line-height: 1.5; + min-height: 48px; + background: transparent; + border: none; + display: flex; + align-items: center; + font-weight: 600; + + &:hover { + background-color: rgba(0,0,0,0.07); + border-radius: 6px; + } + } + + .post-space { + box-shadow: 1px 1px 2px 1px rgba(159,156,156,0.75); + } + + .post-icon { + width: 27px; + } + + &:first-child { + display: flex; + align-items: center; + padding: 8px 16px; + + img { + width: 48px; + margin-right: 8px; + border-radius: 50%; + } + + button { + margin: 4px 0; + flex-grow: 1; + border-radius: 35px; + padding-left: 16px; + border: 1px solid rgba(0,0,0,0,15); + border-radius: 35px; + background-color: #fff; + text-align: left; + } + } + + &:nth-child(2) { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + padding-bottom: 4px; + + button { + img { + margin: 0 4px 0 -2px; + } + + span { + color: #70b5f9; + } + } + } + } +`; + +const Article = styled(CommonCard)` + padding: 0; + margin: 0 0 8px; + overflow: visible; +`; + +const SharedActor = styled.div` + padding-right: 40px; + flex-wrap: nowrap; + padding: 12px 16px 0; + margin-bottom: 8px; + align-items: center; + display: flex; + + a { + margin-right: 12px; + flex-grow: 1; + overflow: hidden; + display: flex; + text-decoration: none; + + img { + width: 48px; + height: 48px; + } + + & > div { + display: flex; + flex-direction: column; + flex-grow: 1; + flex-basis: 0; + margin-left: 8px; + overflow: hidden; + + span { + text-align: left; + + &:first-child { + font-size: 14px; + font-weight: 700; + color: rgba(0, 0, 0, 1); + } + + &:nth-child(n+1) { + font-size: 12px; + color: rgba(0,0,0,0.6); + } + } + } + } + + button { + position: absolute; + right: 12px; + outline: none; + border: none; + top: 0; + background: transparent; + } +`; + +const Description = styled.div` + padding: 0 16px; + overflow: hidden; + color: rgba(0,0,0,0.9); + font-size: 14px; + text-align: left; +`; + +const SharedImage = styled.div` + margin-top: 8px; + width: 100%; + display: block; + position: relative; + background-color: #f9fafb; + + img { + object-fit: contain; + width: 100%; + height: 100%; + } +`; + +const SocialCounts = styled.ul` + line-height: 100%; + display: flex; + align-items: flex-start; + overflow: auto; + list-style: none; + margin: 0 16px; + padding: 8px 0; + border-bottom: 1px solid #e9e5df; + + li { + margin-right: 5px; + font-size: 12px; + + button { + display: flex; + border: none; + background: #fff; + } + } + + img { + width: 18px; + } +`; + +const SocialActions = styled.div` + align-items: center; + display: flex; + justify-content: center; + margin: 0; + min-height: 40px; + padding: 4px 8px; + + button { + display: inline-flex; + align-items: center; + padding: 8px; + color: #0a66c2; + border: none; + background-color: #fff; + + @media (min-width: 768px) { + span { + margin-left: 8px; + } + } + } +`; + +const Content = styled.div` + text-align: center; + & > img { + width: 30px; + } +`; + +const mapStateToProps = (state) => { + return { + loading: state.articleState.loading, + user: state.userState.user, + articles: state.articleState.articles, + } +} + +const mapDispatchToProps = (dispatch) => ({ + getArticles: () => dispatch(getArticlesAPI()), +}) + +export default connect(mapStateToProps, mapDispatchToProps) (Main); \ No newline at end of file diff --git a/src/components/PostModal.js b/src/components/PostModal.js new file mode 100644 index 00000000..8e57e3a2 --- /dev/null +++ b/src/components/PostModal.js @@ -0,0 +1,327 @@ +import { useState } from 'react'; +import styled from 'styled-components'; +import ReactPlayer from 'react-player'; +import { connect } from 'react-redux'; +import firebase from 'firebase'; +import { postArticleAPI } from '../actions'; + +const PostModal = (props) => { + const [editorText, setEditorText] = useState(''); + const [sharedImage, setSharedImage] = useState(''); + const [videoLink, setVideoLink] = useState(''); + const [assetArea, setAssetArea] = useState(''); + + const handleChange = (e) => { + const image = e.target.files[0]; + + if(image === '' || image === undefined) + { + alert(`not an image, the file is a ${typeof image}`); + return; + } + setSharedImage(image); + }; + + const switchAssetArea = (area) => { + setSharedImage(''); + setVideoLink(''); + setAssetArea(area); + }; + + const postArticle = (e) => { + e.preventDefault(); + if(e.target !== e.currentTarget) + { + return; + } + + const payload = { + image: sharedImage, + video: videoLink, + user: props.user, + description: editorText, + timestamp: firebase.firestore.Timestamp.now(), + }; + + props.postArticle(payload); + reset(e); + }; + + const reset = (e) => { + setEditorText(""); + setSharedImage(''); + setVideoLink(''); + setAssetArea(''); + props.handleClick(e); + } + + return ( + <> + { props.showModal === "open" && + + +
+

Create a post

+ +
+ + + + {props.user.photoURL ? ( + + ) : ( + + )} + + {props.user.displayName} + + + + +