Last active
November 17, 2016 00:32
-
-
Save sungwoncho/7f0302d3dc01170da008c63aea64063c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import ReactDOM from 'react-dom'; | |
import { Router, browserHistory } from 'react-router'; | |
import { Provider } from 'react-redux'; | |
import ReactGA from 'react-ga'; | |
import getRoutes from './routes'; | |
import ApiClient from './libs/api_client'; | |
import configureStore from './configureStore'; | |
import { ReduxAsyncConnect } from 'redux-connect'; | |
import { updateLocation } from './actions/router'; | |
const store = configureStore(window.__data); | |
const client = new ApiClient(); | |
ReactGA.initialize('UA-55773666-10'); | |
// logPageview records the current page in the Google Analytics | |
function logPageview() { | |
ReactGA.set({ page: window.location.pathname }); | |
ReactGA.pageview(window.location.pathname); | |
} | |
// hashLinkScroll scrolls the page to appropriate hash location in the page | |
function hashLinkScroll() { | |
const { hash } = window.location; | |
if (hash !== '') { | |
// Push onto callback queue so it runs after the DOM is updated, | |
// this is required when navigating from a different page so that | |
// the element is rendered on the page before trying to getElementById. | |
setTimeout(() => { | |
const id = hash.replace('#', ''); | |
const element = document.getElementById(id); | |
if (element) element.scrollIntoView(); | |
}, 0); | |
} | |
} | |
function handleUpdate() { | |
hashLinkScroll(); | |
// __PRODUCTION__ is a global defined in webpack config | |
if (__PRODUCTION__) { | |
logPageview(); | |
} | |
} | |
function renderRoutes(history) { | |
// store the current router information inside the redux store | |
history.listen((location) => store.dispatch(updateLocation(location))); | |
return ( | |
<Router | |
render={(props) => <ReduxAsyncConnect {...props} helpers={{ client }} />} | |
history={history} | |
onUpdate={handleUpdate} | |
> | |
{getRoutes()} | |
</Router> | |
); | |
} | |
ReactDOM.render(( | |
<Provider store={store}> | |
{renderRoutes(browserHistory)} | |
</Provider> | |
), document.getElementById('react-root')); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
//... | |
"github.com/mssola/user_agent" | |
//... | |
) | |
//... | |
func (i *Impl) CreateCompanyView(w http.ResponseWriter, r *http.Request) { | |
db := i.DB | |
vars := mux.Vars(r) | |
slug := vars["companySlug"] | |
var company models.Company | |
var companyView models.CompanyView | |
// If somehow bot triggered this, then do not increment the view count | |
ua := user_agent.New(r.Header.Get("User-Agent")) | |
if ua.Bot() { | |
return | |
} | |
err := db.Where("slug = ?", slug).First(&company).Error | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
err = db.Where(models.CompanyView{CompanyID: company.ID, Date: time.Now()}). | |
FirstOrCreate(&companyView). | |
Error | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
// Increment | |
companyView.Count = companyView.Count + 1 | |
err = db.Save(&companyView).Error | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
} | |
//... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { asyncConnect } from 'redux-connect'; | |
import { withRouter } from 'react-router'; | |
import ApiClient from '../../libs/api_client'; | |
const client = new ApiClient(); | |
import { fetchCompany, isCompanyLoaded as loaded } from '../../actions/company_item'; | |
import ProfileContent from './profile_content.jsx'; | |
import SignInDialogue from './sign_in_dialogue.jsx'; | |
import { retrieveSingleEntity, retrieveEntities } from '../../libs/state_helpers'; | |
import { areCompanyJobsLoaded, fetchCompanyJobs } from '../../actions/company_jobs'; | |
@asyncConnect([{ | |
promise: ({ store: { getState, dispatch }, params: { companySlug } }) => { | |
const state = getState(); | |
const promises = []; | |
if (!loaded(state, companySlug)) { | |
promises.push(dispatch(fetchCompany(companySlug))); | |
} | |
if (!areCompanyJobsLoaded(state, companySlug)) { | |
promises.push(dispatch(fetchCompanyJobs(companySlug))); | |
} | |
return Promise.all(promises); | |
}, | |
// asyncConnect makes the result of the promise available in redux store under | |
// the given key, but we don't rely on that behavior. Rather, key is provided | |
// to track errors. | |
key: 'companyPromise' | |
}], | |
(state, ownProps) => { | |
const { params: { companySlug } } = ownProps; | |
return { | |
company: retrieveSingleEntity(state, 'companies', companySlug), | |
jobs: retrieveEntities(state, state.companyJobs[companySlug].items, 'jobs'), | |
filterSelection: state.companyFilters.selection, | |
isFetching: state.companyItem.isFetching, | |
user: state.auth.user, | |
followingCompanies: state.followingList.items | |
}; | |
} | |
) | |
class CompanyLayout extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
showSignInDialogue: false, | |
currentTab: 'overview' | |
}; | |
} | |
componentDidMount() { | |
const { params: { companySlug } } = this.props; | |
client.post(`/companies/${companySlug}/company_views`) | |
.catch(err => console.log('Error while incrementing view', err)); | |
} | |
toggleSignInDialogue(display) { | |
this.setState({ showSignInDialogue: display }); | |
} | |
handleSwitchTab(tabName) { | |
this.setState({ currentTab: tabName }); | |
} | |
handleModalClose() { | |
const { router } = this.props; | |
router.goBack(); | |
} | |
render() { | |
const { company, filterSelection, isFetching, user, followingCompanies, isModal, location, jobs, router } = this.props; | |
const { showSignInDialogue } = this.state; | |
const isFollowing = followingCompanies.indexOf(company.slug) > -1; | |
return ( | |
<div className="company-profile-container"> | |
<ProfileContent | |
company={company} | |
filterSelection={filterSelection} | |
user={user} | |
showSignInDialogue={this.toggleSignInDialogue.bind(this, true)} | |
isModal={isModal} | |
location={location} | |
isFollowing={isFollowing} | |
jobs={jobs} | |
handleSwitchTab={this.handleSwitchTab.bind(this)} | |
handleModalClose= {this.handleModalClose.bind(this)} | |
/> | |
{showSignInDialogue ? | |
<SignInDialogue | |
company={company} | |
closeSignInDialogue={this.toggleSignInDialogue.bind(this, false)} | |
/> : null} | |
</div> | |
); | |
} | |
} | |
export default withRouter(CompanyLayout); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { PropTypes } from 'react'; | |
import { renderToString } from 'react-dom/server'; | |
import Helmet from 'react-helmet'; | |
Html.propTypes = { | |
component: PropTypes.node, | |
assets: PropTypes.object | |
}; | |
export default class Html extends React.Component { | |
render() { | |
const { component, assets, store } = this.props; | |
const content = component ? renderToString(component) : ''; | |
const head = Helmet.rewind(); | |
return ( | |
<html lang="en-us"> | |
<head> | |
{head.title.toComponent()} | |
{head.meta.toComponent()} | |
{head.link.toComponent()} | |
<link rel="shortcut icon" href="/favicon.ico" /> | |
<meta name="fragment" content="!" /> | |
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" /> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" integrity="sha384-y3tfxAZXuh4HwSYylfB+J125MxIs6mR5FOHamPBG064zB+AFeWH94NdvaCBm8qnd" crossOrigin="anonymous" /> | |
<script src="https://code.jquery.com/jquery-2.2.2.min.js" integrity="sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=" crossOrigin="anonymous"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.2.0/js/tether.min.js"></script> | |
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/js/bootstrap.min.js"></script> | |
<link href='https://fonts.googleapis.com/css?family=Lato:300,400,500,700,900' rel='stylesheet' type='text/css' /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
{/* styles (will be present only in production with webpack extract text plugin) */} | |
{Object.keys(assets.styles).map((style, key) => | |
<link href={assets.styles[style]} key={key} media="screen, projection" | |
rel="stylesheet" type="text/css" charSet="UTF-8"/> | |
)} | |
<script dangerouslySetInnerHTML={{__html: | |
`if (document.location.hostname.search("localhost") === -1) { | |
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | |
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | |
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | |
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); | |
ga('create', 'UA-55773666-10', 'auto'); | |
ga('send', 'pageview'); | |
}` | |
}} /> | |
{/* (will be present only in development mode) */} | |
{/* outputs a <style/> tag with all bootstrap styles + App.scss + it could be CurrentPage.scss. */} | |
{/* can smoothen the initial style flash (flicker) on page load in development mode. */} | |
{/* ideally one could also include here the style for the current page (Home.scss, About.scss, etc) */} | |
{ Object.keys(assets.styles).length === 0 ? <style dangerouslySetInnerHTML={{__html: require('../styles/main.scss')._style}}/> : null } | |
</head> | |
<body> | |
<div id="react-root" dangerouslySetInnerHTML={{ __html: content }} /> | |
<script dangerouslySetInnerHTML={{__html: `window.__data=${JSON.stringify(store.getState())};`}} charSet="UTF-8"/> | |
<script dangerouslySetInnerHTML={{__html: `(function(){var qs,js,q,s,d=document,gi=d.getElementById,ce=d.createElement,gt=d.getElementsByTagName,id='typef_orm',b='https://s3-eu-west-1.amazonaws.com/share.typeform.com/';if(!gi.call(d,id)){js=ce.call(d,'script');js.id=id;js.src=b+'share.js';q=gt.call(d,'script')[0];q.parentNode.insertBefore(js,q)}id=id+'_';if(!gi.call(d,id)){qs=ce.call(d,'link');qs.rel='stylesheet';qs.id=id;qs.href=b+'share-button.css';s=gt.call(d,'head')[0];s.appendChild(qs,s)}})()`}} /> | |
<script dangerouslySetInnerHTML={{__html: `!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');`}} /> | |
<script src={assets.javascript.main} charSet="UTF-8"/> | |
</body> | |
</html> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment