-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial boilerplate migration to Typescript #62
base: master
Are you sure you want to change the base?
Changes from all commits
cedf7a1
cbef533
948f236
1494b63
7697488
5b50ea1
40f1d7c
d715db1
b988f3b
328279c
c1c7bc6
3a7277f
645fd63
332df35
f1dd63d
19f4f7b
bfe89fa
ec566bf
7ea9c68
98dcd6f
0327be2
a8a36d1
6ae00f7
d478cde
dc9b9e4
101e772
711a11b
470aeef
b7e684a
645d330
c252675
28d0b91
45a775d
14c3e86
0f2fd6c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
declare module '*.svg' | ||
declare module '*.png' | ||
declare module '*.jpg' | ||
|
||
declare module '*.json' |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import './styles/App.global' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import * as React from 'react'; | ||
import {BrowserRouter as Router} from 'react-router-dom'; | ||
import { Switch, Route, Redirect } from 'react-router-dom'; | ||
import { Provider} from 'react-redux'; | ||
|
||
import store from './store'; | ||
import ROUTES from './routes'; | ||
import Header from './components/presentational/Header'; | ||
import { Container } from './components/presentational/Layout'; | ||
|
||
import './App.style' | ||
|
||
class App extends React.Component { | ||
public render() { | ||
return ( | ||
<Provider store={store}> | ||
<Router> | ||
<Container> | ||
<Header /> | ||
<section> | ||
<Switch> | ||
{ROUTES.map(({path, component, exact}) => | ||
<Route key={path} path={path} exact={exact} component={component} />)} | ||
<Redirect to='/home' /> | ||
</Switch> | ||
</section> | ||
</Container> | ||
</Router> | ||
</Provider> | ||
); | ||
} | ||
} | ||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createAction } from 'redux-actions' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
export const FETCH_TRENDING = 'FETCH_TRENDING'; | ||
export const FETCHED_TRENDING = 'FETCHED_TRENDING'; | ||
|
||
export const ADD_FAVORITE = 'ADD_FAVORITE'; | ||
export const REMOVE_FAVORITE = 'REMOVE_FAVORITE' | ||
export const TOGGLE_FAVORITE = 'TOGGLE_FAVORITE'; | ||
|
||
export const SEARCH_TRENDING = 'SEARCH_TRENDING'; | ||
|
||
export const FILTER_FAVS = 'FILTER_FAVS'; | ||
|
||
export const fetch_gifs = createAction(FETCH_TRENDING); | ||
export const fetched_gifs = createAction(FETCHED_TRENDING); | ||
|
||
export const toggle_favorite = createAction(TOGGLE_FAVORITE, (payload: any) => payload); | ||
|
||
export const search_trending = createAction(SEARCH_TRENDING, (payload: any) => payload); | ||
|
||
export const filter_favs = createAction(FILTER_FAVS, (payload: any) => payload); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import axios from 'axios'; | ||
|
||
const API_URL = "https://api.giphy.com/v1/gifs"; | ||
const API_KEY = process.env.REACT_APP_GIPHY_KEY; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
const API = axios.create({ baseURL: API_URL, params: { api_key: API_KEY } }); | ||
|
||
export function getTrending() { | ||
return API.get('/trending'); | ||
} | ||
|
||
export function search(query: string) { | ||
return API.get('/search', { | ||
params: { | ||
q: query, | ||
limit: 25, | ||
offset: 0, | ||
rating: 'G', | ||
lang: 'en' | ||
} | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import styled from 'styled-components'; | ||
import { NavLink as RouterNavLink } from 'react-router-dom'; | ||
|
||
export const StyledNav = styled.nav` | ||
border-bottom: 1px solid #FC4349; | ||
margin-bottom: 1em; | ||
color: #6DBCDB; | ||
font-weight: bold; | ||
|
||
ul { | ||
display: flex; | ||
justify-content: space-around; | ||
text-align: center; | ||
align-items: center; | ||
height: 3.5em; | ||
} | ||
|
||
li { flex: 1; } | ||
|
||
a { | ||
text-decoration: none; | ||
color: inherit; | ||
padding: 1em; | ||
} | ||
`; | ||
|
||
export const NavLink = styled(RouterNavLink)` | ||
&.active { color: #FC4349; } | ||
` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import * as React from 'react'; | ||
import ROUTES from '../routes'; | ||
import Search from './Search'; | ||
|
||
import { StyledNav, NavLink } from './AppNav.style' | ||
|
||
const LINKS = ROUTES.map(({path, content}) => | ||
<li key={path}><NavLink to={path}>{content}</NavLink></li>); | ||
|
||
class AppNav extends React.Component { | ||
public render() { | ||
return (<StyledNav> | ||
<ul> | ||
{LINKS} | ||
<li><Search /></li> | ||
</ul> | ||
</StyledNav>); | ||
} | ||
} | ||
|
||
export default AppNav; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import * as React from 'react'; | ||
import { connect } from 'react-redux'; | ||
import { Dispatch, bindActionCreators } from 'redux'; | ||
|
||
import { filter_favs as filter_favs_action } from '../actions/gifs'; | ||
import { SearchInput } from './Search.style'; | ||
|
||
class FavsSearch extends React.Component<any> { | ||
public onSearch = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
const term = event.target.value; | ||
return this.props.filter_favs(term); | ||
} | ||
|
||
public render() { | ||
return <SearchInput type='text' | ||
onChange={this.onSearch} | ||
placeholder='Search in your favorites...' />; | ||
} | ||
} | ||
|
||
function mapDispatchToProps(dispatch: Dispatch) { | ||
return bindActionCreators({ | ||
filter_favs: filter_favs_action, | ||
}, dispatch); | ||
} | ||
export default connect(null, mapDispatchToProps)(FavsSearch); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const _div_search = styled.div` | ||
width: 100%; | ||
max-width: 320px; | ||
margin: 0 auto; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import * as React from 'react'; | ||
import { IGIF } from '../types'; | ||
import GIFList from './presentational/GIFList'; | ||
import {connect} from 'react-redux'; | ||
import { Dispatch, bindActionCreators } from 'redux'; | ||
import FavsSearch from './FavsSearch'; | ||
|
||
import { _div_search } from './FavsView.style' | ||
|
||
interface IFavsViewProps { | ||
gifs: IGIF[] | ||
} | ||
|
||
export const FavsView = (props: IFavsViewProps) => { | ||
return (<div> | ||
<h1 className="center">Your favorite GIFS</h1> | ||
<_div_search> | ||
<FavsSearch /> | ||
</_div_search> | ||
<GIFList gifs={props.gifs} /> | ||
</div>); | ||
} | ||
|
||
function filterFavs(favs: object, query: string) { | ||
const gifs = Object.keys(favs).map(key => favs[key]); | ||
|
||
// Don't filter if there is no query term | ||
if (!query || query.length === 0) return gifs; | ||
|
||
return gifs.filter((gif: IGIF) => gif.title.includes(query)); | ||
} | ||
|
||
function mapStateToProps(state: any) { | ||
return { gifs: filterFavs(state.favs, state.filter_favs) } | ||
} | ||
export default connect(mapStateToProps)(FavsView); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this specific case where we have few routes that are at the same level the benefit may not be that obvious, but remember that the mindset of React-router 4 is making routing dynamic instead of static. When defining your routes on a separate file you are still approaching this in a static way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, should I move them to this single file?
Although, the dynamic routing could still be used in any other file connecting with router right?
I'm used to use single-file definitions for routes at the same level and use multiple files (dynamic) for nested routes or with a different context.