app/javascript/components/external/vcwiz/global/competitors/competitor_base.jsx
import React from 'react';
import ProfileImage from '../shared/profile_image';
import {
CompetitorFundTypes, CompetitorIndustries, InvestorsPath, OutreachPath,
InvestorPath, CompanyPath, IntroPathTypes, CompetitorsListsPath,
MediumScreenSize, FirmPath
} from '../constants.js.erb';
import {Row, Column} from 'react-foundation';
import {
ffetch, fullName, isLoggedIn, isMobile, nullOrUndef, sendEvent,
withDots,
} from '../utils';
import Actions from '../actions';
import Store from '../store';
import PartnerTab from './partner_tab';
import IconLine from '../shared/icon_line';
import showdown from 'showdown';
import inflection from 'inflection';
import Tabs from '../tabs/tabs';
import FakeLink from '../shared/fake_link';
import fetchCompetitorPath from '../fetch_competitor_path';
import IntroPathCount from './intro_path_count';
import PartnerHeading from './partner_heading';
import createHistory from 'history/createBrowserHistory'
import {canUseDOM} from 'exenv';
export default class CompetitorBase extends React.Component {
constructor(props) {
super(props);
this.converter = new showdown.Converter();
this.state = {
tab: null,
path: null,
dimensions: Store.get('dimensions', {
width: 0,
height: 0,
}),
};
this.firstTabChange = true;
if (canUseDOM) {
this.history = createHistory();
this.originalLocation = window.location.pathname;
}
}
componentWillMount() {
this.mounted = true;
this.subscription = Store.subscribe('dimensions', dimensions => this.setState({dimensions}));
}
componentWillUnmount() {
this.mounted = false;
Store.unsubscribe(this.subscription);
if (this.props.item.id) {
if (this.history) {
this.history.push(this.originalLocation);
}
}
}
componentDidMount() {
if (this.props.item.id) {
if (this.history) {
let tab = document.location.hash && parseInt(document.location.hash.substr(1), 10);
if (!this.props.item.partners || tab >= this.props.item.partners.length) {
tab = undefined;
}
const path = FirmPath.resource(this.props.item.id, inflection.dasherize(this.props.item.name.toLowerCase()));
if (this.history.location.pathname !== path) {
this.history.push({pathname: path, hash: tab ? tab.toString() : null});
}
if (!this.props.tab && tab) {
this.onTabChange(tab);
}
}
if (!isLoggedIn()) {
return;
}
sendEvent('competitor_clicked', this.props.item.id);
fetchCompetitorPath(this.props.item.id, path => {
if (this.mounted && !_.isEmpty(path)) {
this.setState({path});
}
});
}
}
onTrackChange = id => update => {
if (this.props.onTrackChange) {
this.props.onTrackChange(update);
} else {
const { target_investors } = Store.get('founder', {});
const target = _.find(target_investors, {competitor_id: this.props.item.id});
if (!target) {
Actions.trigger('flash', {type: 'success', message: `${this.props.item.name} has been added to your conversation tracker!`, link: OutreachPath});
}
ffetch(InvestorsPath.id(id), 'PATCH', {investor: {stage: update.track.value}}).then(() => {
Actions.trigger('refreshFounder');
});
}
};
onTabChange = i => {
this.setState({tab: i});
if (this.firstTabChange) {
this.firstTabChange = false;
} else {
const partner = this.props.item.partners[i];
if (partner) {
sendEvent('investor_clicked', partner.id);
}
if (this.history) {
this.history.push({hash: i.toString()});
}
}
};
renderHeading() {
const { name, photo, hq, fund_type } = this.props.item;
const type = _.first(fund_type) && [
<span key="type">{CompetitorFundTypes[_.first(fund_type)]}</span>,
<span key="dot">ยท</span>,
];
return (
<div className="competitor-heading">
<ProfileImage src={photo} size={50} className="inline-image" rounded={false} />
<div className="heading">{name}</div>
<div className="subheading">
{type || null}
<span>{hq}</span>
</div>
</div>
);
}
renderCompany({ id, name }) {
return <a href={CompanyPath.resource(id, inflection.dasherize(name.toLowerCase()))}>{name}</a>;
}
renderCompetitor({ id, name }) {
return <a href={FirmPath.resource(id, inflection.dasherize(name.toLowerCase()))}>{name}</a>;
}
renderIndustries() {
const { industry } = this.props.item;
if (!industry || !industry.length) {
return null;
}
let industries = _.take(industry, isMobile() ? 3 : 7).map(i =>
<span key={i}>{CompetitorIndustries[i]}</span>
);
return <p><b className="info-heading">Top Industries:</b> {withDots(industries)}</p>
}
renderInvestments() {
const { recent_investments } = this.props.item;
if (!recent_investments || !recent_investments.length) {
return null;
}
let investments = _.take(recent_investments, isMobile() ? 3 : 5).map(c =>
<span key={c.id}>{this.renderCompany(c)}</span>
);
return <p><b className="info-heading">Recent Investments:</b> {withDots(investments)}</p>
}
renderCoinvestors() {
const { coinvestors } = this.props.item;
if (!coinvestors || !coinvestors.length) {
return null;
}
let competitors = _.take(coinvestors, isMobile() ? 3 : 5).map(c =>
<span key={c.id}>{this.renderCompetitor(c)}</span>
);
return <p><b className="info-heading">Co-Investors:</b> {withDots(competitors)}</p>
}
renderPath() {
const { path } = this.state;
if (!_.get(path, 'count')) {
return null;
}
return <IntroPathCount {...path} path={IntroPathTypes.COMPETITOR} id={this.props.item.id} />;
}
renderCompetitorInfo() {
const { description } = this.props.item;
return (
<div className="competitor-info">
<div
className="description scroll-shadow"
dangerouslySetInnerHTML={{ __html: this.converter.makeHtml(description) }}
/>
{this.renderIndustries()}
{this.renderInvestments()}
{this.renderCoinvestors()}
</div>
);
}
renderIconLine(icon, line, link = null, text = null) {
return <IconLine icon={icon} line={line} link={link} text={text}/>;
}
renderCompetitorSocial() {
let { al_url, cb_url, crunchbase_id, facebook, twitter, domain } = this.props.item;
return (
<div className="competitor-social">
{this.renderIconLine('icn-al', '', al_url, al_url && _.last(al_url.split('/')))}
{this.renderIconLine('icn-cb', '', cb_url, crunchbase_id)}
{this.renderIconLine('web', domain, 'http://')}
{this.renderIconLine('social-facebook', facebook, 'https://fb.com')}
{this.renderIconLine('social-twitter', twitter && `@${twitter}`, 'https://twitter.com')}
</div>
)
}
renderBottom() {
const { tab, item } = this.props;
const { dimensions, tab: currentTab } = this.state;
const { partners, matches } = item;
if (!partners || !partners.length) {
return null;
}
let defaultIndex = tab || _.findIndex(partners, {id: _.first(matches)});
if (defaultIndex === -1) {
defaultIndex = undefined;
}
const index = nullOrUndef(currentTab) ? (defaultIndex || 0) : currentTab;
if (partners.length > 1 && dimensions.width > MediumScreenSize) {
this.firstTabChange = false;
return (
<Row className="sidebar-wrapper">
<Column large={2} className="sidebar-list">
{partners.map((p, i) =>
<div key={i} onClick={() => this.onTabChange(i)}>
<PartnerHeading investor={p} short={true} transparency="F5F6F7" className={i === index ? 'active' : undefined} size={45} />
</div>
)}
</Column>
<Column large={10}><PartnerTab key={index} onTrackChange={this.onTrackChange(partners[index].id)} investor={partners[index]} /></Column>
</Row>
);
} else {
return (
<Tabs
scrollShadows={true}
defaultIndex={defaultIndex}
tabs={partners.map(p => <FakeLink href={InvestorPath.resource(p.id, inflection.dasherize(fullName(p).toLowerCase()))} value={fullName(p)} />)}
panels={partners.map(p => <PartnerTab onTrackChange={this.onTrackChange(p.id)} investor={p} />)}
onTabChange={this.onTabChange}
/>
);
}
}
renderTop() {
return (
<Row>
<Column large={9}>
{this.renderHeading()}
{this.renderPath()}
{this.renderCompetitorInfo()}
</Column>
<Column large={3}>
{this.renderCompetitorSocial()}
</Column>
</Row>
);
}
}