<commit_before>import * as search from 'searchtabular';
import React, { Component } from 'react';
import Item from './Item';
import SearchBar from './Search';
import { compose } from 'redux';
import { multiInfix } from '../../helpers/utils';

class List extends Component {

	render() {
    const { query, rows } = this.props;
    const columns = this.props.fields.map((field) => field={
      property: field.name,
      header: {
        label: field.label,
      },
      filterType:field.filterType,
    });

    const searchExecutor = search.multipleColumns({
      columns,
      query,
      strategy: multiInfix });
    const visibleItems = compose(searchExecutor)(rows);

		return (

 List View

			 <SearchBar
          filter={this.props.filter}
          fields={this.props.fields}
          onFilter={this.props.onFilter}
        />
        {visibleItems.map(item =>
          <Item
            item={item}
            fields={this.props.fields}
            onEdit={this.props.onEdit}
            onDelete={this.props.onDelete}
            key={item.id}
          />
        )}

		);
	}
}

export default List;<commit_msg>Cleaned up formatting<commit_after>import * as search from 'searchtabular';
import React, { Component } from 'react';
import Item from './Item';
import SearchBar from './Search';
import { compose } from 'redux';
import { multiInfix } from '../../helpers/utils';

class List extends Component {

	render() {
    const { query, rows } = this.props;
    const columns = this.props.fields.map((field) => ({
      property: field.name,
      header: {
        label: field.label,
      },
      filterType:field.filterType,
    }));

    const searchExecutor = search.multipleColumns({
      columns,
      query,
      strategy: multiInfix });
    const visibleItems = compose(searchExecutor)(rows);

		return (

 List View

			 <SearchBar
          filter={this.props.filter}
          fields={this.props.fields}
          onFilter={this.props.onFilter}
        />
        {visibleItems.map(item =>
          <Item
            item={item}
            fields={this.props.fields}
            onEdit={this.props.onEdit}
            onDelete={this.props.onDelete}
            key={item.id}
          />
        )}

		);
	}
}

export default List;<|endoftext|>


<commit_before>import React, { Component } from 'react'
import styled from 'styled-components'
import { RESPONSIVE_BREAKPOINT } from '../util/constants'
import DrawerContainer from '../containers/DrawerContainer'

const drawerWidth = '256px'

const Outer = styled.div`
  @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
    overflow-x: hidden;
  }

  @media (min-width: ${RESPONSIVE_BREAKPOINT}) {
    display: flex;
    flex-direction: row;
  }
`

const Drawer = styled.div`
  background: #fff;
  z-index: 10;

  @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
    height: 100vh;
    width: ${drawerWidth};
    position: fixed;
    top: 0;
    transition: left .2s ease-in;
    left: ${({ isOpen }) => isOpen ? '0' : `-${drawerWidth}`}
  }

  @media (min-width: ${RESPONSIVE_BREAKPOINT}) {
    width: ${drawerWidth};
  }
`

const Content = styled.main`
  height: 100vh;
  overflow: scroll;

  @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
    position: relative;
    left: 0;
    transition: left .2s ease-in;

    ${({ isOpen }) => {
      if (isOpen) {
        return `
          left: ${drawerWidth};
          width: 100vw;
        `
      }
    }}
  }

  @media (min-width: ${RESPONSIVE_BREAKPOINT}) {
    flex: 1;
  }
`

class DrawerLayout extends Component {
  render () {
    return (
      <Outer>
        <Drawer isOpen={this.props.isDrawerOpen}>
          <DrawerContainer />
        </Drawer>
        <Content isOpen={this.props.isDrawerOpen}>
          {this.props.children}
        </Content>
      </Outer>
    )
  }
}

export default DrawerLayout
<commit_msg>Fix infinite scroll<commit_after>import React, { Component } from 'react'
import styled from 'styled-components'
import { RESPONSIVE_BREAKPOINT } from '../util/constants'
import DrawerContainer from '../containers/DrawerContainer'

const drawerWidth = '256px'

const Outer = styled.div`
  @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
    overflow-x: hidden;
  }

  @media (min-width: ${RESPONSIVE_BREAKPOINT}) {
    display: flex;
    flex-direction: row;
  }
`

const Drawer = styled.div`
  background: #fff;
  z-index: 10;

  @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
    height: 100vh;
    width: ${drawerWidth};
    position: fixed;
    top: 0;
    transition: left .2s ease-in;
    left: ${({ isOpen }) => isOpen ? '0' : `-${drawerWidth}`}
  }

  @media (min-width: ${RESPONSIVE_BREAKPOINT}) {
    width: ${drawerWidth};
  }
`

const Content = styled.main`
  min-height: 100vh;

  @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
    position: relative;
    left: 0;
    transition: left .2s ease-in;

    ${({ isOpen }) => {
      if (isOpen) {
        return `
          left: ${drawerWidth};
          width: 100vw;
        `
      }
    }}
  }

  @media (min-width: ${RESPONSIVE_BREAKPOINT}) {
    flex: 1;
  }
`

class DrawerLayout extends Component {
  render () {
    return (
      <Outer>
        <Drawer isOpen={this.props.isDrawerOpen}>
          <DrawerContainer />
        </Drawer>
        <Content isOpen={this.props.isDrawerOpen}>
          {this.props.children}
        </Content>
      </Outer>
    )
  }
}

export default DrawerLayout
<|endoftext|>


<commit_before>import React from 'react'

import Panel from 'components/Panel'
import './footer.css'

const Footer = () => (
  <Panel
    tag="footer"
    className="footer"
  >
    <Panel
      tag="section"
      className="footer__content"
      inset="l"
      between="m"
      row
      justify="space-around"
    >
      GitHub
      Link
      Outro link
    </Panel>
  </Panel>
)

export default Footer
<commit_msg>fix(FOOTER): corrigir footer<commit_after>import React from 'react'

import Panel from 'components/Panel'
import './footer.css'

const Footer = () => (
  <Panel
    tag="footer"
    className="footer"
  >
    <Panel
      tag="section"
      className="footer__content"
      inset="l"
      between="m"
      row
      justify="space-around"
    >
      Sobre nós
      GitHub
      Powered By DarkSky
    </Panel>
  </Panel>
)

export default Footer
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { render } from 'react-dom';
import Color from 'color';

import $ from 'jquery';
import 'fullcalendar';
import 'fullcalendar/dist/gcal.js';
import 'fullcalendar/dist/fullcalendar.css';
import uniqueId from 'lodash/uniqueId';

import CalendarEvent from './CalendarEvent.js';

import { BREAKPOINTS, COLORS, OPACITIES } from '../constants.js';

const fcButtonHoverBackgroundColor = new Color(COLORS.ACCENT).alpha(OPACITIES.SECONDARY);

export default class FullCalendar extends Component {
	constructor(props){
		super(props);
		this.state = {
			calendarId: uniqueId()
		};

		this.createCalendar = this.createCalendar.bind(this);
		this.destroyCalendar = this.destroyCalendar.bind(this);
		this.getCalendarState = this.getCalendarState.bind(this);
		this.receiveMessage = this.receiveMessage.bind(this);
	}

	render() {
		return (

		);
	}

	shouldComponentUpdate(nextProps){
		if (this.props.apiKey !== nextProps.apiKey)
			return true;

		let eventSourcesToAdd = nextProps.eventSources.filter(newEventSource =>
			!this.props.eventSources.some(oldEventSource =>
				oldEventSource.googleCalendarId === newEventSource.googleCalendarId
					&& oldEventSource.color === newEventSource.color)
		);

		let eventSourcesToRemove = this.props.eventSources.filter(oldEventSource =>
			!nextProps.eventSources.some(newEventSource =>
				newEventSource.googleCalendarId === oldEventSource.googleCalendarId
					&& newEventSource.color === oldEventSource.color)
		);

		const calendar = $(`#${this.state.calendarId}`);

		if (eventSourcesToRemove && eventSourcesToRemove.length > 0)
			calendar.fullCalendar('removeEventSources', eventSourcesToRemove);

		if (eventSourcesToAdd && eventSourcesToAdd.length > 0){
			eventSourcesToAdd.map(eventSourceToAdd => {
				calendar.fullCalendar('addEventSource', eventSourceToAdd);
			});
		}

		if (nextProps.location && nextProps.location.search) {
			let params = new URLSearchParams(nextProps.location.search.slice(1));

			let viewName = params.get('view');
			let viewDate = params.get('date');

			if (
				this.getGenericViewName(viewName) !== this.getGenericViewName(this.viewName)
				|| viewDate !== this.viewDate
			) {
				this.viewName = viewName;
				this.viewDate = viewDate;
				$(`#${this.state.calendarId}`)
					.fullCalendar(
						'changeView',
						this.getSpecificViewName(viewName),
						viewDate
					);
			}
		}

		return false;
	}

	componentDidMount() {
		this.createCalendar();

		if (this.props.trustedOrigins && this.props.trustedOrigins.includes('*')) {
			window.addEventListener('message', this.receiveMessage, false);
		}
	}

	componentWillReceiveProps(nextProps) {
		const { eventId, setActiveEvent } = this.props;

		const calendar = $(`#${this.state.calendarId}`);

		if (nextProps.eventId && nextProps.eventId !== eventId) {
			let events = calendar.fullCalendar('clientEvents', nextProps.eventId);
			if (events.length > 0) {
				setActiveEvent(events[0]);
			}
		}
	}

	componentWillUpdate() {
		this.destroyCalendar();
	}

	componentDidUpdate() {
		this.createCalendar();
	}

	componentWillUnmount() {
		this.destroyCalendar();
		window.removeEventListener('message', this.receiveMessage);
	}

	receiveMessage(event) {
		// Allow extracting calendar state by posting message from trusted origin,
		// useful when calendar is embedded in iframe.

		if (this.props.trustedOrigins && (
			this.props.trustedOrigins.includes('*')
			|| this.props.trustedOrigins.includes(event.origin)
		)) {
			event.source.postMessage({
				view: this.viewName,
				date: this.viewDate
			}, event.origin);
		}
	}

	getGenericViewName(viewName) {
		switch (viewName) {
			case 'listWeek':
			case 'basicWeek':
				return 'week';
			default:
				return viewName;
		}
	}

	getSpecificViewName(viewName) {
		switch (viewName) {
			case 'week':
				return window.innerWidth > BREAKPOINTS.SMALL_DESKTOP
					? 'basicWeek'
					: 'listWeek';
			default:
				return viewName;
		}
	}

	getCalendarState(view) {
		if (!this.props.history)
			return;

		let viewDate = view.intervalStart.toString();

		if (
			this.getSpecificViewName(this.viewName) !== view.name
			|| this.viewDate !== viewDate
		) {
			let newLocation = Object.assign({}, this.props.location);
			let params = new URLSearchParams(newLocation.search.slice(1));
			params.set('view', view.name);
			params.set('date', viewDate);

			newLocation.search = params.toString();

			this.viewName = view.name;
			this.viewDate = view.intervalStart.toString();
			this.props.history.push(newLocation);
		}
	}

	destroyCalendar() {
		$(`#${this.state.calendarId}`).fullCalendar('destroy');
	}

	createCalendar() {
		const { eventId, setActiveEventId, setActiveEvent, defaultDate } = this.props;
		let { defaultView } = this.props;

		if (defaultView)
			defaultView = this.getSpecificViewName(defaultView);
		else
			defaultView = window.innerWidth > BREAKPOINTS.SMALL_DESKTOP
				? 'month'
				: 'listWeek';

		this.viewName = defaultView;
		this.viewDate = defaultDate;

		const calendar = $(`#${this.state.calendarId}`);
		const getCalendarState = this.getCalendarState;

		calendar.fullCalendar(Object.assign({
			googleCalendarApiKey: this.props.apiKey,
			eventSources: this.props.eventSources,
			height: 'auto',
			fixedWeekCount: false,
			header: {
				left: 'title',
				center: 'month,listWeek,basicWeek,agendaDay',
				right: 'today prev,next'
			},
			defaultView,
			defaultDate,
			navLinks: true,
			eventRender(calEvent, element, view){
				let container, calEventElement;
				if (view && view.name && view.name.startsWith('list')) {
					container = document.createElement('tr');
					calEventElement = 'td';
				} else {
					container = document.createElement('div');
					calEventElement = 'div';
				}

				container.className = 'event-container';

				if (view && view.name && view.name.startsWith('agenda'))
					container.style.position = 'absolute';

				render(<CalendarEvent event={calEvent} view={view}
					setActiveEventId={setActiveEventId}
					setActiveEvent={setActiveEvent}
					containerElement={calEventElement} />,
					container);
				return container;
			},
			loading(isLoading) {
				if (!isLoading) {
					if (eventId) {
						let events = calendar.fullCalendar('clientEvents', eventId);
						if (events.length > 0) {
							setActiveEvent(events[0]);
						}
					}
				}
			},
			viewRender: getCalendarState
		}, this.props.fullcalendarConfig));
	}
}

FullCalendar.propTypes = {
	trustedOrigins: PropTypes.array,
	apiKey: PropTypes.string.isRequired,
	eventSources: PropTypes.array.isRequired,
	setActiveEventId: PropTypes.func,
	setActiveEvent: PropTypes.func,
	eventId: PropTypes.string,
	fullcalendarConfig: PropTypes.object,
	defaultView: PropTypes.string,
	defaultDate: PropTypes.string,

	location: PropTypes.shape({
		search: PropTypes.string
	}),
	history: PropTypes.shape({
		push: PropTypes.func.isRequired,
		listen: PropTypes.func.isRequired
	})
};
<commit_msg>Fix bug where '*' was a required trusted origin<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { render } from 'react-dom';
import Color from 'color';

import $ from 'jquery';
import 'fullcalendar';
import 'fullcalendar/dist/gcal.js';
import 'fullcalendar/dist/fullcalendar.css';
import uniqueId from 'lodash/uniqueId';

import CalendarEvent from './CalendarEvent.js';

import { BREAKPOINTS, COLORS, OPACITIES } from '../constants.js';

const fcButtonHoverBackgroundColor = new Color(COLORS.ACCENT).alpha(OPACITIES.SECONDARY);

export default class FullCalendar extends Component {
	constructor(props){
		super(props);
		this.state = {
			calendarId: uniqueId()
		};

		this.createCalendar = this.createCalendar.bind(this);
		this.destroyCalendar = this.destroyCalendar.bind(this);
		this.getCalendarState = this.getCalendarState.bind(this);
		this.receiveMessage = this.receiveMessage.bind(this);
	}

	render() {
		return (

		);
	}

	shouldComponentUpdate(nextProps){
		if (this.props.apiKey !== nextProps.apiKey)
			return true;

		let eventSourcesToAdd = nextProps.eventSources.filter(newEventSource =>
			!this.props.eventSources.some(oldEventSource =>
				oldEventSource.googleCalendarId === newEventSource.googleCalendarId
					&& oldEventSource.color === newEventSource.color)
		);

		let eventSourcesToRemove = this.props.eventSources.filter(oldEventSource =>
			!nextProps.eventSources.some(newEventSource =>
				newEventSource.googleCalendarId === oldEventSource.googleCalendarId
					&& newEventSource.color === oldEventSource.color)
		);

		const calendar = $(`#${this.state.calendarId}`);

		if (eventSourcesToRemove && eventSourcesToRemove.length > 0)
			calendar.fullCalendar('removeEventSources', eventSourcesToRemove);

		if (eventSourcesToAdd && eventSourcesToAdd.length > 0){
			eventSourcesToAdd.map(eventSourceToAdd => {
				calendar.fullCalendar('addEventSource', eventSourceToAdd);
			});
		}

		if (nextProps.location && nextProps.location.search) {
			let params = new URLSearchParams(nextProps.location.search.slice(1));

			let viewName = params.get('view');
			let viewDate = params.get('date');

			if (
				this.getGenericViewName(viewName) !== this.getGenericViewName(this.viewName)
				|| viewDate !== this.viewDate
			) {
				this.viewName = viewName;
				this.viewDate = viewDate;
				$(`#${this.state.calendarId}`)
					.fullCalendar(
						'changeView',
						this.getSpecificViewName(viewName),
						viewDate
					);
			}
		}

		return false;
	}

	componentDidMount() {
		this.createCalendar();

		if (this.props.trustedOrigins) {
			window.addEventListener('message', this.receiveMessage, false);
		}
	}

	componentWillReceiveProps(nextProps) {
		const { eventId, setActiveEvent } = this.props;

		const calendar = $(`#${this.state.calendarId}`);

		if (nextProps.eventId && nextProps.eventId !== eventId) {
			let events = calendar.fullCalendar('clientEvents', nextProps.eventId);
			if (events.length > 0) {
				setActiveEvent(events[0]);
			}
		}
	}

	componentWillUpdate() {
		this.destroyCalendar();
	}

	componentDidUpdate() {
		this.createCalendar();
	}

	componentWillUnmount() {
		this.destroyCalendar();
		window.removeEventListener('message', this.receiveMessage);
	}

	receiveMessage(event) {
		// Allow extracting calendar state by posting message from trusted origin,
		// useful when calendar is embedded in iframe.

		if (this.props.trustedOrigins && (
			this.props.trustedOrigins.includes('*')
			|| this.props.trustedOrigins.includes(event.origin)
		)) {
			event.source.postMessage({
				view: this.viewName,
				date: this.viewDate
			}, event.origin);
		}
	}

	getGenericViewName(viewName) {
		switch (viewName) {
			case 'listWeek':
			case 'basicWeek':
				return 'week';
			default:
				return viewName;
		}
	}

	getSpecificViewName(viewName) {
		switch (viewName) {
			case 'week':
				return window.innerWidth > BREAKPOINTS.SMALL_DESKTOP
					? 'basicWeek'
					: 'listWeek';
			default:
				return viewName;
		}
	}

	getCalendarState(view) {
		if (!this.props.history)
			return;

		let viewDate = view.intervalStart.toString();

		if (
			this.getSpecificViewName(this.viewName) !== view.name
			|| this.viewDate !== viewDate
		) {
			let newLocation = Object.assign({}, this.props.location);
			let params = new URLSearchParams(newLocation.search.slice(1));
			params.set('view', view.name);
			params.set('date', viewDate);

			newLocation.search = params.toString();

			this.viewName = view.name;
			this.viewDate = view.intervalStart.toString();
			this.props.history.push(newLocation);
		}
	}

	destroyCalendar() {
		$(`#${this.state.calendarId}`).fullCalendar('destroy');
	}

	createCalendar() {
		const { eventId, setActiveEventId, setActiveEvent, defaultDate } = this.props;
		let { defaultView } = this.props;

		if (defaultView)
			defaultView = this.getSpecificViewName(defaultView);
		else
			defaultView = window.innerWidth > BREAKPOINTS.SMALL_DESKTOP
				? 'month'
				: 'listWeek';

		this.viewName = defaultView;
		this.viewDate = defaultDate;

		const calendar = $(`#${this.state.calendarId}`);
		const getCalendarState = this.getCalendarState;

		calendar.fullCalendar(Object.assign({
			googleCalendarApiKey: this.props.apiKey,
			eventSources: this.props.eventSources,
			height: 'auto',
			fixedWeekCount: false,
			header: {
				left: 'title',
				center: 'month,listWeek,basicWeek,agendaDay',
				right: 'today prev,next'
			},
			defaultView,
			defaultDate,
			navLinks: true,
			eventRender(calEvent, element, view){
				let container, calEventElement;
				if (view && view.name && view.name.startsWith('list')) {
					container = document.createElement('tr');
					calEventElement = 'td';
				} else {
					container = document.createElement('div');
					calEventElement = 'div';
				}

				container.className = 'event-container';

				if (view && view.name && view.name.startsWith('agenda'))
					container.style.position = 'absolute';

				render(<CalendarEvent event={calEvent} view={view}
					setActiveEventId={setActiveEventId}
					setActiveEvent={setActiveEvent}
					containerElement={calEventElement} />,
					container);
				return container;
			},
			loading(isLoading) {
				if (!isLoading) {
					if (eventId) {
						let events = calendar.fullCalendar('clientEvents', eventId);
						if (events.length > 0) {
							setActiveEvent(events[0]);
						}
					}
				}
			},
			viewRender: getCalendarState
		}, this.props.fullcalendarConfig));
	}
}

FullCalendar.propTypes = {
	trustedOrigins: PropTypes.array,
	apiKey: PropTypes.string.isRequired,
	eventSources: PropTypes.array.isRequired,
	setActiveEventId: PropTypes.func,
	setActiveEvent: PropTypes.func,
	eventId: PropTypes.string,
	fullcalendarConfig: PropTypes.object,
	defaultView: PropTypes.string,
	defaultDate: PropTypes.string,

	location: PropTypes.shape({
		search: PropTypes.string
	}),
	history: PropTypes.shape({
		push: PropTypes.func.isRequired,
		listen: PropTypes.func.isRequired
	})
};
<|endoftext|>


<commit_before>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';

import Label from './Label';

const clean = (value) => `${value}`.replace(/[^0-9.]/g, '');

const decimals = (value, decimals) => `${value.toFixed(decimals)}`;

const currency = (value) => `$ ${decimals(value, 2)}`;

class NumericInput extends React.Component {
    constructor(props) {
        super(props);

        this.id = uniqueId('NumericInput-');

        this.validationMessage = `${props.description} is required`;

        this.state = this.validate(props.value, true);

        this.onBlur = this.onBlur.bind(this);
        this.onChange = this.onChange.bind(this);
        this.onFocus = this.onFocus.bind(this);
    }

    componentWillMount() {
        if (this.props.onValidation) {
            this.props.onValidation(
                this.state.hasValidated,
                this.state.isValid,
                this.state.validationMessage
            );
        }
    }

    onBlur(event) {

        const newState = this.validate(event.target.value, true);
        newState.hasValidated = true;

        this.setState(newState);

        if (this.props.onValidation) {
            this.props.onValidation(
                newState.hasValidated,
                newState.isValid,
                newState.validationMessage
            );
        }

        if (this.props.onChange && newState.value !== this.state.value) {
            this.props.onChange(newState.value);
        }
    }

    onChange(event) {
        const newState = this.validate(event.target.value);
        newState.hasValidated = this.state.hasValidated;

        this.setState(newState);

        if (this.props.onValidation && newState.hasValidated) {
            this.props.onValidation(
                newState.hasValidated,
                newState.isValid,
                newState.validationMessage
            );
        }

        if (this.props.onChange && newState.value !== this.state.value) {
            this.props.onChange(newState.value);
        }
    }

    onFocus(event) {
        const newState = this.validate(event.target.value);
        newState.hasValidated = this.state.hasValidated;

        newState.value = newState.value.replace(/[^0-9.]/g, '');

        this.setState(newState);
    }

    validate(newValue, format = false) {
        let value = parseFloat(clean(newValue));

        const notANumber = Number.isNaN(value);

        if (notANumber) {
            value = '';
        } else if (format && this.props.isCurrency) {
            value = currency(value);
        } else if (format && (this.props.decimals || this.props.decimals === 0)) {
            value = decimals(value, this.props.decimals);
        } else {
            value = `${value}`;
        }

        const isValid = !this.props.required || (!notANumber || !!value);

        return {
            value,
            isValid,
            validationMessage: isValid ? null : this.validationMessage,
            hasValidated:      false,
        };
    }

    render() {
        return (

                {this.props.label
                    ?
                    : ''
                }
                <input
                    type="text"
                    id={this.id}
                    className="form-control"
                    placeholder={this.props.placeholder || ''}
                    value={this.state.value}
                    onBlur={this.onBlur}
                    onChange={this.onChange}
                    onFocus={this.onFocus}
                />

        );
    }
}

// set the property types for the NumericInput component
//
NumericInput.propTypes = {
    label:        React.PropTypes.string,
    description:  React.PropTypes.string,
    required:     React.PropTypes.bool,
    placeholder:  React.PropTypes.string,
    value:        React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    onChange:     React.PropTypes.func,
    onValidation: React.PropTypes.func,
};

export default NumericInput;
<commit_msg>implemented clean function<commit_after>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';

import Label from './Label';

const clean = (value) => `${value}`.replace(/[^0-9.]/g, '');

const decimals = (value, decimals) => `${value.toFixed(decimals)}`;

const currency = (value) => `$ ${decimals(value, 2)}`;

class NumericInput extends React.Component {
    constructor(props) {
        super(props);

        this.id = uniqueId('NumericInput-');

        this.validationMessage = `${props.description} is required`;

        this.state = this.validate(props.value, true);

        this.onBlur = this.onBlur.bind(this);
        this.onChange = this.onChange.bind(this);
        this.onFocus = this.onFocus.bind(this);
    }

    componentWillMount() {
        if (this.props.onValidation) {
            this.props.onValidation(
                this.state.hasValidated,
                this.state.isValid,
                this.state.validationMessage
            );
        }
    }

    onBlur(event) {

        const newState = this.validate(event.target.value, true);
        newState.hasValidated = true;

        this.setState(newState);

        if (this.props.onValidation) {
            this.props.onValidation(
                newState.hasValidated,
                newState.isValid,
                newState.validationMessage
            );
        }

        if (this.props.onChange && newState.value !== this.state.value) {
            this.props.onChange(newState.value);
        }
    }

    onChange(event) {
        const newState = this.validate(event.target.value);
        newState.hasValidated = this.state.hasValidated;

        this.setState(newState);

        if (this.props.onValidation && newState.hasValidated) {
            this.props.onValidation(
                newState.hasValidated,
                newState.isValid,
                newState.validationMessage
            );
        }

        if (this.props.onChange && newState.value !== this.state.value) {
            this.props.onChange(newState.value);
        }
    }

    onFocus(event) {
        const newState = this.validate(event.target.value);
        newState.hasValidated = this.state.hasValidated;

        newState.value = clean(newState.value);

        this.setState(newState);
    }

    validate(newValue, format = false) {
        let value = parseFloat(clean(newValue));

        const notANumber = Number.isNaN(value);

        if (notANumber) {
            value = '';
        } else if (format && this.props.isCurrency) {
            value = currency(value);
        } else if (format && (this.props.decimals || this.props.decimals === 0)) {
            value = decimals(value, this.props.decimals);
        } else {
            value = `${value}`;
        }

        const isValid = !this.props.required || (!notANumber || !!value);

        return {
            value,
            isValid,
            validationMessage: isValid ? null : this.validationMessage,
            hasValidated:      false,
        };
    }

    render() {
        return (

                {this.props.label
                    ?
                    : ''
                }
                <input
                    type="text"
                    id={this.id}
                    className="form-control"
                    placeholder={this.props.placeholder || ''}
                    value={this.state.value}
                    onBlur={this.onBlur}
                    onChange={this.onChange}
                    onFocus={this.onFocus}
                />

        );
    }
}

// set the property types for the NumericInput component
//
NumericInput.propTypes = {
    label:        React.PropTypes.string,
    description:  React.PropTypes.string,
    required:     React.PropTypes.bool,
    placeholder:  React.PropTypes.string,
    value:        React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    onChange:     React.PropTypes.func,
    onValidation: React.PropTypes.func,
};

export default NumericInput;
<|endoftext|>


<commit_before>/** @jsx React.DOM */
"use strict";
var React = require("react/addons");
var Question = require("./Question");

module.exports = React.createClass({
  displayName: "QuestionList",

  getInitialState () {
    return {
      selectedIndex: -1,
      items: this.props.items
    };
  },

  componentWillReceiveProps (nextProps) {
    this.setState({
      items: nextProps.items
    });
  },

  render () {
    return this._render(this.props, this.state);
  },

  _handleClick (i, event) {
    if (i !== this.state.selectedIndex) {
      this.setState({ selectedIndex: i });
    } else {
      this.setState({ selectedIndex: -1 });
    }
  },

  _handleSort (event) {
    var {items} = this.state;
    switch(event.target.id) {
      case 'sortBySign':
        items.sort(function (a, b) {
          return b.signatures.length - a.signatures.length;
        });
        break;
      case 'sortByTime':
        items.sort(function (a, b) {
          return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
        });
        break;
      default:
    }
    this.setState({items});
  },

  _render (props, state) {
    var {items} = state;
    var result = items.map((item, index) => {
      var boundClick = this._handleClick.bind(this, index);
      var selected = (index === state.selectedIndex)? true: false;
      if(props.selected === item.id && -1 === state.selectedIndex) {
        selected = true;
      }
      return <Question key={item.id}
                       selected={selected}
                       index={index}
                       question={item}
                       _handleClick={boundClick}
                       cid={props.candidate.id}
                       pid={props.policy.id}
                       qid={item.id}
                       loggedIn={props.loggedIn}
                       status={props.status} />;
    });

    return

{'共有 ' + items.length + ' 題'}

               <input id="sortBySign" type="radio" name="radios" defaultChecked={true} onClick={this._handleSort} />

               票數排序

            <input id="sortByTime" type="radio" name="radios" onClick={this._handleSort} />

               時間排序

      {result}

;
  }
});<commit_msg>chore(QuestionList): remove sorting menu temporarily<commit_after>/** @jsx React.DOM */
"use strict";
var React = require("react/addons");
var Question = require("./Question");

module.exports = React.createClass({
  displayName: "QuestionList",

  getInitialState () {
    return {
      selectedIndex: -1,
      items: this.props.items
    };
  },

  componentWillReceiveProps (nextProps) {
    this.setState({
      items: nextProps.items
    });
  },

  render () {
    return this._render(this.props, this.state);
  },

  _handleClick (i, event) {
    if (i !== this.state.selectedIndex) {
      this.setState({ selectedIndex: i });
    } else {
      this.setState({ selectedIndex: -1 });
    }
  },

  _handleSort (event) {
    var {items} = this.state;
    switch(event.target.id) {
      case 'sortBySign':
        items.sort(function (a, b) {
          return b.signatures.length - a.signatures.length;
        });
        break;
      case 'sortByTime':
        items.sort(function (a, b) {
          return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
        });
        break;
      default:
    }
    this.setState({items});
  },

  _render (props, state) {
    var {items} = state;
    var result = items.map((item, index) => {
      var boundClick = this._handleClick.bind(this, index);
      var selected = (index === state.selectedIndex)? true: false;
      if(props.selected === item.id && -1 === state.selectedIndex) {
        selected = true;
      }
      return <Question key={item.id}
                       selected={selected}
                       index={index}
                       question={item}
                       _handleClick={boundClick}
                       cid={props.candidate.id}
                       pid={props.policy.id}
                       qid={item.id}
                       loggedIn={props.loggedIn}
                       status={props.status} />;
    });
    var sortingMenu =

               <input id="sortBySign" type="radio" name="radios" defaultChecked={true} onClick={this._handleSort} />

               票數排序

            <input id="sortByTime" type="radio" name="radios" onClick={this._handleSort} />

               時間排序

;

    return

{'共有 ' + items.length + ' 題'}

      {result}

;
  }
});<|endoftext|>


<commit_before>import React, { Component } from "react"
import Typography from "material-ui/Typography"
import Paper from "material-ui/Paper"
import { getWeekArray } from "./../utils/DateHelper"
import ScheduleEvent from "./ScheduleEvent"
import { withStyles, createStyleSheet } from "material-ui/styles"
import PropTypes from "prop-types"

const styleSheet = createStyleSheet("ScheduleView", theme => ({
  dayPaper: {
    display: "flex",
    padding: "15px",
    marginBottom: "5px"
  },

  date: {
    width: "100px"
  }
}))

class ScheduleView extends Component {
  generateWeek = () => {
    const classes = this.props.classes
    let currentDate = this.props.currentDateRange
    let week = getWeekArray(
      currentDate.month,
      currentDate.year,
      currentDate.week
    )
    let view = []
    for (let i = 0; i < week.length; i++) {
      if (Object.is(week[i].day, this.props.currentDateRange.day)) {
        view.push(
          <Paper
            key={"dayPaper" + i + Math.random()}
            elevation={0}
            ref={"event" + this.props.currentDateRange.day}
            className={classes.dayPaper}
          >

              <Typography type="display2" aria-hidden="true">
                {week[i].day}
              </Typography>
              <Typography type="display1" aria-hidden="true">
                {week[i].dayName}
              </Typography>

              {
                <ScheduleEvent
                  day={week[i].day}
                  month={week[i].month}
                  events={this.props.events}
                />
              }

          </Paper>
        )
      } else {
        view.push(
          <Paper
            key={"dayPaper" + i + Math.random()}
            elevation={0}
            className={classes.dayPaper}
          >

              <Typography type="display2" aria-hidden="true">
                {week[i].day}
              </Typography>
              <Typography type="display1" aria-hidden="true">
                {week[i].dayName}
              </Typography>

              {
                <ScheduleEvent
                  day={week[i].day}
                  month={week[i].month}
                  events={this.props.events}
                />
              }

          </Paper>
        )
      }
    }
    return view
  }

  render() {
    return (

        {this.generateWeek()}

    )
  }
}

ScheduleView.propTypes = {
  classes: PropTypes.object.isRequired
}

export default withStyles(styleSheet)(ScheduleView)
<commit_msg>Change aria-label to read full date #23<commit_after>import React, { Component } from "react"
import Typography from "material-ui/Typography"
import Paper from "material-ui/Paper"
import { getWeekArray } from "./../utils/DateHelper"
import ScheduleEvent from "./ScheduleEvent"
import { withStyles, createStyleSheet } from "material-ui/styles"
import PropTypes from "prop-types"
import { monthNames } from "./../utils/Strings"

const styleSheet = createStyleSheet("ScheduleView", theme => ({
  dayPaper: {
    display: "flex",
    padding: "15px",
    marginBottom: "5px"
  },

  date: {
    width: "100px"
  }
}))

class ScheduleView extends Component {
  generateWeek = () => {
    const classes = this.props.classes
    let currentDate = this.props.currentDateRange
    let week = getWeekArray(
      currentDate.month,
      currentDate.year,
      currentDate.week
    )
    let view = []
    for (let i = 0; i < week.length; i++) {
      if (Object.is(week[i].day, this.props.currentDateRange.day)) {
        view.push(
          <Paper
            key={"dayPaper" + i + Math.random()}
            elevation={0}
            ref={"event" + this.props.currentDateRange.day}
            className={classes.dayPaper}
          >

              <Typography type="display2" aria-hidden="true">
                {week[i].day}
              </Typography>
              <Typography type="display1" aria-hidden="true">
                {week[i].dayName}
              </Typography>

              {
                <ScheduleEvent
                  day={week[i].day}
                  month={week[i].month}
                  events={this.props.events}
                />
              }

          </Paper>
        )
      } else {
        view.push(
          <Paper
            key={"dayPaper" + i + Math.random()}
            elevation={0}
            className={classes.dayPaper}
          >

              <Typography type="display2" aria-hidden="true">
                {week[i].day}
              </Typography>
              <Typography type="display1" aria-hidden="true">
                {week[i].dayName}
              </Typography>

              {
                <ScheduleEvent
                  day={week[i].day}
                  month={week[i].month}
                  events={this.props.events}
                />
              }

          </Paper>
        )
      }
    }
    return view
  }

  render() {
    return (

        {this.generateWeek()}

    )
  }
}

ScheduleView.propTypes = {
  classes: PropTypes.object.isRequired
}

export default withStyles(styleSheet)(ScheduleView)
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Link } from 'react-router-dom'

import { withFirebase } from '../Firebase'
import * as ROUTES from '../../constants/routes'

const SignUpPage = () => (

SignUp

    <SignUpForm />

)

const INITIAL_STATE = {
  username: '',
  email: '',
  passwordOne: '',
  passwordTwo: '',
  error: null,
}

class SignUpFormBase extends Component {
  constructor(props) {
    super(props)
    this.state = { ...INITIAL_STATE }
  }

  onSubmit = event => {
    const { username, email, passwordOne } = this.state
    this.props.firebase
      .doCreateUserWithEmailAndPassword(email, passwordOne)
      .then(authUser => {
        this.setState({ ...INITIAL_STATE })
      })
      .catch(error => {
        this.setState({ error })
      })
    event.preventDefault()
  }

  onChange = event => {
    this.setState({ [event.target.name]: event.target.value })
  }

  render() {
    const { username, email, passwordOne, passwordTwo, error } = this.state
    const isInvalid =
      passwordOne !== passwordTwo ||
      passwordOne === '' ||
      email === '' ||
      username === ''

    return (
      <form onSubmit={this.onSubmit}>
        <input
          name="username"
          value={username}
          onChange={this.onChange}
          type="text"
          placeholder="Full Name"
        />
        <input
          name="email"
          value={email}
          onChange={this.onChange}
          type="text"
          placeholder="Email Address"
        />
        <input
          name="passwordOne"
          value={passwordOne}
          onChange={this.onChange}
          type="password"
          placeholder="Password"
        />
        <input
          name="passwordTwo"
          value={passwordTwo}
          onChange={this.onChange}
          type="password"
          placeholder="Confirm Password"
        />
        <button disabled={isInvalid} type="submit">
          Sign Up
        </button>
        {error &&
{error.message}
}
      </form>
    )
  }
}

const SignUpLink = () => (

    Don't have an account? <Link to={ROUTES.SIGN_UP}>Sign Up</Link>

)

const SignUpForm = withFirebase(SignUpFormBase)

export default SignUpPage
export { SignUpForm, SignUpLink }
<commit_msg>Added redirection logic to SignUp component<commit_after>import React, { Component } from 'react'
import { Link, withRouter } from 'react-router-dom'

import { withFirebase } from '../Firebase'
import * as ROUTES from '../../constants/routes'

const SignUpPage = () => (

SignUp

    <SignUpForm />

)

const INITIAL_STATE = {
  username: '',
  email: '',
  passwordOne: '',
  passwordTwo: '',
  error: null,
}

class SignUpFormBase extends Component {
  constructor(props) {
    super(props)
    this.state = { ...INITIAL_STATE }
  }

  onSubmit = event => {
    const { username, email, passwordOne } = this.state
    this.props.firebase
      .doCreateUserWithEmailAndPassword(email, passwordOne)
      .then(authUser => {
        this.setState({ ...INITIAL_STATE })
        this.props.history.push(ROUTES.HOME)
      })
      .catch(error => {
        this.setState({ error })
      })
    event.preventDefault()
  }

  onChange = event => {
    this.setState({ [event.target.name]: event.target.value })
  }

  render() {
    const { username, email, passwordOne, passwordTwo, error } = this.state
    const isInvalid =
      passwordOne !== passwordTwo ||
      passwordOne === '' ||
      email === '' ||
      username === ''

    return (
      <form onSubmit={this.onSubmit}>
        <input
          name="username"
          value={username}
          onChange={this.onChange}
          type="text"
          placeholder="Full Name"
        />
        <input
          name="email"
          value={email}
          onChange={this.onChange}
          type="text"
          placeholder="Email Address"
        />
        <input
          name="passwordOne"
          value={passwordOne}
          onChange={this.onChange}
          type="password"
          placeholder="Password"
        />
        <input
          name="passwordTwo"
          value={passwordTwo}
          onChange={this.onChange}
          type="password"
          placeholder="Confirm Password"
        />
        <button disabled={isInvalid} type="submit">
          Sign Up
        </button>
        {error &&
{error.message}
}
      </form>
    )
  }
}

const SignUpLink = () => (

    Don't have an account? <Link to={ROUTES.SIGN_UP}>Sign Up</Link>

)

const SignUpForm = withRouter(withFirebase(SignUpFormBase))

export default SignUpPage
export { SignUpForm, SignUpLink }
<|endoftext|>


<commit_before>const React = require('react')
const { Component, PropTypes } = React
const d3 = require('d3')
const { curry, uniq, clone } = require('ramda')
const { isNumberArray, isBooleanArray } = require('../model/classifier')
const { numericChart } = require('../viz/numeric-chart')
const { categoricalChart } = require('../viz/categorical-chart')
const { booleanChart } = require('../viz/boolean-chart')
const table = require('../model/table')
const { ofLength, selectRange, sortedBy } = require('../model/selection')
const { ensureG } = require('../viz/utils')

const chartFn = (column) => {
  if (isBooleanArray(column)) return booleanChart
  if (isNumberArray(column)) return numericChart
  return categoricalChart
}

const reduceOne = (c, name, index) => {
  const column = c(index)
  const cf = chartFn(column)
  const config = {name, className: name, top: 20, left: 50 * index}
  if (cf === categoricalChart) {
    config['keys'] = uniq(column).sort()
  }
  return { index, cf, column, config }
}

const reduce = (c, dataTable, columnNames) => {
  var packets = []
  for (var i = 0; i
 {
  const myG = g.append('g')
   .classed('title', true)
   .attr('transform', () => `translate(${left}, 15)`)
   .on('click', click)

  myG.selectAll('rect')
    .data([0])
    .enter().append('rect')
    .style('x', 0)
    .style('y', -10)
    .style('width', 40)
    .style('height', 10)
    .style('fill-opacity', 0)

  myG.selectAll('text')
    .data([name])
    .enter().append('text')
    .text((d) => d.substr(0, 7))
    .append('svg:title')
    .text((d) => d)
}

let dragStart

class StripesChart extends Component {
  displayName: 'StripesChart'

  propTypes: {
    dataTable: PropTypes.array.isRequired,
    columnNames: PropTypes.array.isRequired
  }

  setSelection(selection) {
    this.selection = selection
    const g = d3.select(this.refs.chart)
      .selectAll('svg')
      .selectAll('#root')
    this.drawSelection(g)
  }

  drawSelection(g) {
    const top   = 20
    const left  = 0
    const width = 50 * table.width(this.dataTable)

    const myG = ensureG(g, 'selection', left, top)
    const update = myG.selectAll('rect')
      .data(this.selection, (d, i) => i)

    const enter = update.enter()
    enter
      .append('rect')
      .classed('hilite', true)
      .classed('selected', d => d)
      .classed('unselected', d => !d)
      .style('y',      (d, i) => i)
      .style('x',      left)
      .style('width',  width)
      .style('height', 1)
      .on('mousedown', (d, i) => {
        dragStart = i
        this.setSelection(ofLength(table.height(this.dataTable)))
      })
      .on('mouseup', (d, i) => {
        const low = Math.min(dragStart, i)
        const high = Math.max(dragStart, i)
        this.setSelection(selectRange(ofLength(table.height(this.dataTable)), low, high))
      })

    update
      .classed('selected', d => d)
      .classed('unselected', d => !d)
      .style('y',      (d, i) => i)
  }

  drawChart(g) {
    const { columnNames } = this.props
    const c = curry(table.column)(this.dataTable, i => i)
    const packets = reduce(c, this.dataTable, columnNames)
    packets.forEach(({ index, cf, column, config }) => {
      const click = () => {
        this.updateThings(index)
      }
      drawTitle(g, config.name, config.left, click)
      cf(g, column, config)
    })
  }

  componentDidMount() {
    this.dataTable = clone(this.props.dataTable)
    this.selection = ofLength(table.height(this.dataTable))
    this.doThings()
  }

  componentDidUpdate() {
    this.updateThings()
  }

  setContext() {
    return d3.select(this.refs.chart).append('svg')
    .attr('id', 'should-be-a-prop')
    .attr('width', table.width(this.dataTable) * 50)
    .attr('height', table.height(this.dataTable) + 50)
    .append('g')
    .attr('id', 'root')
  }

  doThings() {
    const g = this.setContext()
    this.drawSelection(g)
    this.drawChart(g)
  }

  updateThings(index) {
    const rank = table.byColumn(this.dataTable, index)
    this.dataTable = table.sortedByColumn(this.dataTable, index)
    this.selection = sortedBy(rank, this.selection)
    const g = d3.select(this.refs.chart)
      .selectAll('svg')
      .selectAll('#root')
    this.drawSelection(g)
    this.drawChart(g)
  }

  render() {
    return (

    )
  }
}

export default StripesChart
<commit_msg>improves feedback while selecting<commit_after>const React = require('react')
const { Component, PropTypes } = React
const d3 = require('d3')
const { curry, uniq, clone } = require('ramda')
const { isNumberArray, isBooleanArray } = require('../model/classifier')
const { numericChart } = require('../viz/numeric-chart')
const { categoricalChart } = require('../viz/categorical-chart')
const { booleanChart } = require('../viz/boolean-chart')
const table = require('../model/table')
const { ofLength, selectRange, sortedBy } = require('../model/selection')
const { ensureG } = require('../viz/utils')

const chartFn = (column) => {
  if (isBooleanArray(column)) return booleanChart
  if (isNumberArray(column)) return numericChart
  return categoricalChart
}

const reduceOne = (c, name, index) => {
  const column = c(index)
  const cf = chartFn(column)
  const config = {name, className: name, top: 20, left: 50 * index}
  if (cf === categoricalChart) {
    config['keys'] = uniq(column).sort()
  }
  return { index, cf, column, config }
}

const reduce = (c, dataTable, columnNames) => {
  var packets = []
  for (var i = 0; i
 {
  const myG = g.append('g')
   .classed('title', true)
   .attr('transform', () => `translate(${left}, 15)`)
   .on('click', click)

  myG.selectAll('rect')
    .data([0])
    .enter().append('rect')
    .style('x', 0)
    .style('y', -10)
    .style('width', 40)
    .style('height', 10)
    .style('fill-opacity', 0)

  myG.selectAll('text')
    .data([name])
    .enter().append('text')
    .text((d) => d.substr(0, 7))
    .append('svg:title')
    .text((d) => d)
}

let dragStart = undefined

class StripesChart extends Component {
  displayName: 'StripesChart'

  propTypes: {
    dataTable: PropTypes.array.isRequired,
    columnNames: PropTypes.array.isRequired
  }

  setSelection(selection) {
    this.selection = selection
    const g = d3.select(this.refs.chart)
      .selectAll('svg')
      .selectAll('#root')
    this.drawSelection(g)
  }

  drawSelection(g) {
    const top   = 20
    const left  = 0
    const width = 50 * table.width(this.dataTable)

    const myG = ensureG(g, 'selection', left, top)
    const update = myG.selectAll('rect')
      .data(this.selection, (d, i) => i)

    const enter = update.enter()
    enter
      .append('rect')
      .classed('hilite', true)
      .classed('selected', d => d)
      .classed('unselected', d => !d)
      .style('y',      (d, i) => i)
      .style('x',      left)
      .style('width',  width)
      .style('height', 1)
      .on('mousedown', (d, i) => {
        dragStart = i
        this.setSelection(ofLength(table.height(this.dataTable)))
      })
      .on('mouseup', (d, i) => {
        const low = Math.min(dragStart, i)
        const high = Math.max(dragStart, i)
        dragStart = undefined
        this.setSelection(selectRange(ofLength(table.height(this.dataTable)), low, high))
      })

      .on('mousemove', (d, i) => {
        if (dragStart === undefined) return
        const low = Math.min(dragStart, i)
        const high = Math.max(dragStart, i)
        this.setSelection(selectRange(ofLength(table.height(this.dataTable)), low, high))
      })

    update
      .classed('selected', d => d)
      .classed('unselected', d => !d)
      .style('y',      (d, i) => i)
  }

  drawChart(g) {
    const { columnNames } = this.props
    const c = curry(table.column)(this.dataTable, i => i)
    const packets = reduce(c, this.dataTable, columnNames)
    packets.forEach(({ index, cf, column, config }) => {
      const click = () => {
        this.updateThings(index)
      }
      drawTitle(g, config.name, config.left, click)
      cf(g, column, config)
    })
  }

  componentDidMount() {
    this.dataTable = clone(this.props.dataTable)
    this.selection = ofLength(table.height(this.dataTable))
    this.doThings()
  }

  componentDidUpdate() {
    this.updateThings()
  }

  setContext() {
    return d3.select(this.refs.chart).append('svg')
    .attr('id', 'should-be-a-prop')
    .attr('width', table.width(this.dataTable) * 50)
    .attr('height', table.height(this.dataTable) + 50)
    .append('g')
    .attr('id', 'root')
  }

  doThings() {
    const g = this.setContext()
    this.drawSelection(g)
    this.drawChart(g)
  }

  updateThings(index) {
    const rank = table.byColumn(this.dataTable, index)
    this.dataTable = table.sortedByColumn(this.dataTable, index)
    this.selection = sortedBy(rank, this.selection)
    const g = d3.select(this.refs.chart)
      .selectAll('svg')
      .selectAll('#root')
    this.drawSelection(g)
    this.drawChart(g)
  }

  render() {
    return (

    )
  }
}

export default StripesChart
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Table, Column, Cell } from 'fixed-data-table-2';
import 'fixed-data-table-2/dist/fixed-data-table.css';
import classnames from 'classnames';

import {
  table,
  cell,
  cellCenter,
  r,
  d,
  i,
  yea,
  nay,
  voteText,
  antiskew,
} from '../stylesheets/tableWrapper.css';
import Phone from './Phone';

const partyClass = party => ({
  [r]: party === 'Republican',
  [d]: party === 'Democrat',
  [i]: party === 'Independent',
});

const voteClass = vote => ({
  [yea]: vote === 'Yea',
  [nay]: vote === 'Nay',
});

const voteRepr = (vote) => {
  switch (vote) {
  case 'Yea':
    return '✓';
  case 'Nay':
    return '✗';
  default:
    return '';
  }
};

const headerize = (text) => {
  return text.split(' ').map((textchunk, ind) => {
    return { `${textchunk} ` }; // eslint-disable-line react/no-array-index-key, max-len
  });
};

export default class TableWrapper extends Component {
  render() {
    const { senators, votes, voteTotals, filteredVoteRecords, children } = this.props;

    return (

          <Column // Names of senators
            width={ 200 }
            header={ children }
            cell={ (props) => {
              if (senators) {
                const senator = senators[props.rowIndex];
                return (
                  <Cell className={ classnames(cell, partyClass(senator.party)) }>
                    { senator.lastName }
                  </Cell>
                );
              } else {
                return <Cell />;
              }
            } }
          />
          <Column // States of senators
            width={ 50 }
            header={ () => <Cell className={ cell } style={ { paddingTop: '6px' } }>{ headerize('State') }</Cell> }
            cell={ (props) => {
              if (senators) {
                const senator = senators[props.rowIndex];
                return (
                  <Cell className={ classnames(cell, partyClass(senator.party)) }>
                    { senator.state }
                  </Cell>
                );
              } else {
                return <Cell />;
              }
            } }
          />
          <Column // Contact links of senators
            width={ 40 }
            header={ () => <Cell className={ cell }>{ headerize('Contact') }</Cell> }
            cell={ (props) => {
              if (senators) {
                const senator = senators[props.rowIndex];
                return (
                  <Cell className={ classnames(cell, partyClass(senator.party)) }>

                    <Phone number={ senator.phone } name={ senator.name } />
                  </Cell>
                );
              } else {
                return <Cell />;
              }
            } }
          />
          <Column // Record on votes so far
            width={ 70 }
            header={ () => (
              <Cell className={ cell } style={ { paddingTop: '13px' } } >
                { headerize('Record (yeas / total)') }
              </Cell>
            ) }
            cell={ (props) => {
              const senator = senators[props.rowIndex];
              return (
                <Cell className={ classnames(cellCenter, partyClass(senator.party)) }>
                  { voteTotals[senator.name] } / { voteTotals.total }
                </Cell>
              );
            } }
          />
          { Object.entries(filteredVoteRecords).map(([voteId, votersForVote]) => {
            return (
              <Column // The vote on each nominee
                key={ voteId }
                width={ 62 }
                header={ () => <Cell className={ cell }>{ headerize(votes[voteId].question) }</Cell> }
                cell={ (props) => {
                  if (votersForVote[props.rowIndex]) {
                    const vote = votersForVote[props.rowIndex].value;
                    return (
                      <Cell className={ classnames(cellCenter, voteClass(vote)) }>
                        { voteRepr(vote) }
                        { vote }
                      </Cell>
                    );
                  } else {
                    return null;
                  }
                } }
              />
            );
          })}

    );
  }
}
<commit_msg>Rein in table width<commit_after>import React, { Component } from 'react';
import { Table, Column, Cell } from 'fixed-data-table-2';
import 'fixed-data-table-2/dist/fixed-data-table.css';
import classnames from 'classnames';

import {
  table,
  cell,
  cellCenter,
  r,
  d,
  i,
  yea,
  nay,
  voteText,
  antiskew,
} from '../stylesheets/tableWrapper.css';
import Phone from './Phone';

const partyClass = party => ({
  [r]: party === 'Republican',
  [d]: party === 'Democrat',
  [i]: party === 'Independent',
});

const voteClass = vote => ({
  [yea]: vote === 'Yea',
  [nay]: vote === 'Nay',
});

const voteRepr = (vote) => {
  switch (vote) {
  case 'Yea':
    return '✓';
  case 'Nay':
    return '✗';
  default:
    return '';
  }
};

const headerize = (text) => {
  return text.split(' ').map((textchunk, ind) => {
    return { `${textchunk} ` }; // eslint-disable-line react/no-array-index-key, max-len
  });
};

export default class TableWrapper extends Component {
  render() {
    const { senators, votes, voteTotals, filteredVoteRecords, children } = this.props;

    let tableWidth = (Object.entries(filteredVoteRecords).length * 62) + (200 + 50 + 40 + 70) + 120;
    if (tableWidth < window.innerWidth) {
      tableWidth = window.innerWidth;
    }

    return (

          <Column // Names of senators
            width={ 200 }
            header={ children }
            cell={ (props) => {
              if (senators) {
                const senator = senators[props.rowIndex];
                return (
                  <Cell className={ classnames(cell, partyClass(senator.party)) }>
                    { senator.lastName }
                  </Cell>
                );
              } else {
                return <Cell />;
              }
            } }
          />
          <Column // States of senators
            width={ 50 }
            header={ () => <Cell className={ cell } style={ { paddingTop: '6px' } }>{ headerize('State') }</Cell> }
            cell={ (props) => {
              if (senators) {
                const senator = senators[props.rowIndex];
                return (
                  <Cell className={ classnames(cell, partyClass(senator.party)) }>
                    { senator.state }
                  </Cell>
                );
              } else {
                return <Cell />;
              }
            } }
          />
          <Column // Contact links of senators
            width={ 40 }
            header={ () => <Cell className={ cell }>{ headerize('Contact') }</Cell> }
            cell={ (props) => {
              if (senators) {
                const senator = senators[props.rowIndex];
                return (
                  <Cell className={ classnames(cell, partyClass(senator.party)) }>

                    <Phone number={ senator.phone } name={ senator.name } />
                  </Cell>
                );
              } else {
                return <Cell />;
              }
            } }
          />
          <Column // Record on votes so far
            width={ 70 }
            header={ () => (
              <Cell className={ cell } style={ { paddingTop: '13px' } } >
                { headerize('Record (yeas / total)') }
              </Cell>
            ) }
            cell={ (props) => {
              const senator = senators[props.rowIndex];
              return (
                <Cell className={ classnames(cellCenter, partyClass(senator.party)) }>
                  { voteTotals[senator.name] } / { voteTotals.total }
                </Cell>
              );
            } }
          />
          { Object.entries(filteredVoteRecords).map(([voteId, votersForVote]) => {
            return (
              <Column // The vote on each nominee
                key={ voteId }
                width={ 62 }
                header={ () => <Cell className={ cell }>{ headerize(votes[voteId].question) }</Cell> }
                cell={ (props) => {
                  if (votersForVote[props.rowIndex]) {
                    const vote = votersForVote[props.rowIndex].value;
                    return (
                      <Cell className={ classnames(cellCenter, voteClass(vote)) }>
                        { voteRepr(vote) }
                        { vote }
                      </Cell>
                    );
                  } else {
                    return null;
                  }
                } }
              />
            );
          })}

    );
  }
}
<|endoftext|>


<commit_before>import { isObservableArray } from 'mobx'
import { attachToContract, sendTXToContract } from '../../utils/blockchainHelpers'
import { contractStore, crowdsaleStore, generalStore, tierStore, tokenStore, web3Store } from '../../stores'
import { TRUNC_TO_DECIMALS, VALIDATION_TYPES } from '../../utils/constants'
import { floorToDecimals, toFixed } from '../../utils/utils'
import { toBigNumber } from '../crowdsale/utils'

const { VALID } = VALIDATION_TYPES

const formatDate = timestamp => {
  const ten = i => (i < 10 ? '0' : '') + i
  const date = new Date(timestamp * 1000)
  const YYYY = date.getFullYear()
  const MM = ten(date.getMonth() + 1)
  const DD = ten(date.getDate())
  const HH = ten(date.getHours())
  const II = ten(date.getMinutes())

  return YYYY + '-' + MM + '-' + DD + 'T' + HH + ':' + II
}

export const updateTierAttribute = (attribute, value, addresses) => {
  const { decimals } = tokenStore
  let methods = {
    startTime: 'setStartsAt',
    endTime: 'setEndsAt',
    supply: 'setMaximumSellableTokens',
    rate: 'updateRate',
    whitelist: 'setEarlyParticipantWhitelistMultiple'
  }
  let abi
  let contractAddresses

  if (attribute === 'startTime' || attribute === 'endTime' || attribute === 'supply' || attribute === 'whitelist') {
    abi = contractStore.crowdsale.abi
    contractAddresses = [addresses.crowdsaleAddress]

    if (attribute === 'startTime' || attribute === 'endTime') {
      value = [toFixed(parseInt(Date.parse(value) / 1000, 10).toString())]
    } else if (attribute === 'supply') {
      value = [toBigNumber(value).times(`1e${tokenStore.decimals}`).toFixed()]
    } else {
      // whitelist
      value = value.reduce((toAdd, whitelist) => {
        toAdd[0].push(whitelist.addr)
        toAdd[1].push(true)
        toAdd[2].push(whitelist.min * 10 ** decimals ? toFixed((whitelist.min * 10 ** decimals).toString()) : 0)
        toAdd[3].push(whitelist.max * 10 ** decimals ? toFixed((whitelist.max * 10 ** decimals).toString()) : 0)
        return toAdd
      }, [[], [], [], []])
    }
  }

  if (attribute === 'rate') {
    abi = contractStore.crowdsale.abi
    contractAddresses = [addresses.crowdsaleAddress]
    const oneTokenInETH = floorToDecimals(TRUNC_TO_DECIMALS.DECIMALS18, 1 / Number(value))
    value = [web3Store.web3.utils.toWei(oneTokenInETH, 'ether')]
  }

  if (!contractAddresses) return Promise.reject('no updatable value')

  if (attribute === 'whitelist') {
    const totalTiers = tierStore.tiers.length
    const currentTierIndex = crowdsaleStore.selected.initialTiersValues
      .findIndex(tier => tier.addresses.crowdsaleAddress === addresses.crowdsaleAddress)

    if (currentTierIndex <= totalTiers - 1) {
      contractAddresses = crowdsaleStore.selected.initialTiersValues
        .slice(currentTierIndex)
        .map(tier => tier.addresses.crowdsaleAddress)
    }
  }

  return contractAddresses.reduce((promise, contractAddress) => {
    return promise.then(() => {
      return attachToContract(abi, contractAddress)
        .then(contract => {
          const method = contract.methods[methods[attribute]]

          return method(...value).estimateGas()
            .then(estimatedGas => {
              return sendTXToContract(method(...value)
                .send({
                  gasLimit: estimatedGas,
                  gasPrice: generalStore.gasPrice
                })
              )
            })
        })
    })
  }, Promise.resolve())
}

const extractWhitelistInformation = (isWhitelisted, crowdsaleMethods) => {
  let whitelistedAccounts = []
  const whenWhitelistedAddresses = []

  if (isWhitelisted && crowdsaleMethods.whitelistedParticipantsLength) {
    return crowdsaleMethods.whitelistedParticipantsLength().call()
      .then(participantsCount => {
        for (let participantIndex = 0; participantIndex < participantsCount; participantIndex++) {
          whenWhitelistedAddresses.push(crowdsaleMethods.whitelistedParticipants(participantIndex).call())
        }

        return Promise.all(whenWhitelistedAddresses)
      })
      .then(whitelistedAddresses => {
        const whenAccountData = whitelistedAddresses
          .map(address => crowdsaleMethods.earlyParticipantWhitelist(address).call())

        return Promise.all(whenAccountData)
          .then(accountData => [isWhitelisted, whitelistedAddresses, accountData])
      })
  }

  return Promise.resolve([isWhitelisted, whenWhitelistedAddresses, whitelistedAccounts])
}

const crowdsaleData = crowdsaleAddress => {
  return attachToContract(contractStore.crowdsale.abi, crowdsaleAddress)
    .then(crowdsaleContract => {
      const { methods } = crowdsaleContract
      const whenToken = methods.token().call()
      const whenMultisigWallet = methods.multisigWallet().call()
      const whenStartsAt = methods.startsAt().call()
      const whenEndsAt = methods.endsAt().call()
      const whenIsUpdatable = methods.isUpdatable().call()
      const whenIsWhitelisted = methods.isWhiteListed().call()
      const whenMaximumSellableTokens = methods.maximumSellableTokens().call()
      const whenPricingStrategy = methods.pricingStrategy().call()
      const whenIsFinalized = methods.finalized().call()
      const whenName = methods.name().call()

      return whenIsWhitelisted
        .then(isWhitelisted => extractWhitelistInformation(isWhitelisted, methods))
        .then(([whitelisted, whitelistedAddresses, accountData]) => {
          const whitelistedAccounts = accountData.map((data, index) => {
            return {
              addr: whitelistedAddresses[index],
              min: data.minCap,
              max: data.maxCap
            }
          })

          return Promise.all([whitelisted, whitelistedAccounts])
        })
        .then(([isWhitelisted, whitelistAccounts]) => {
          return Promise.all([
            whenToken,
            whenMultisigWallet,
            whenStartsAt,
            whenEndsAt,
            whenIsUpdatable,
            isWhitelisted,
            whenMaximumSellableTokens,
            whenPricingStrategy,
            whenIsFinalized,
            whenName,
            whitelistAccounts
          ])
        })
    })
}

const tokenData = tokenAddress => {
  return attachToContract(contractStore.token.abi, tokenAddress)
    .then(tokenContract => {
      const { methods } = tokenContract
      const whenName = methods.name().call()
      const whenSymbol = methods.symbol().call()
      const whenDecimals = methods.decimals().call()

      return Promise.all([whenName, whenSymbol, whenDecimals])
    })
}

const pricingStrategyData = pricingStrategyAddress => {
  return attachToContract(contractStore.pricingStrategy.abi, pricingStrategyAddress)
    .then(pricingStrategyContract => pricingStrategyContract.methods.oneTokenInWei().call())
}

export const getTiers = crowdsaleAddress => {
  return attachToContract(contractStore.crowdsale.abi, crowdsaleAddress)
    .then(crowdsaleContract => {
      const { methods } = crowdsaleContract

      return methods.joinedCrowdsalesLen().call()
        .then(joinedCrowdsalesLen => {
          let joinedCrowdsales = []

          for (let joinedTierIndex = 0; joinedTierIndex < joinedCrowdsalesLen; joinedTierIndex++) {
            joinedCrowdsales.push(methods.joinedCrowdsales(joinedTierIndex).call())
          }

          return Promise.all(joinedCrowdsales)
        })
    })
}

export const processTier = (crowdsaleAddress, crowdsaleNum) => {
  const { web3 } = web3Store

  const newTier = {
    whitelist: []
  }

  const initialValues = {}

  return crowdsaleData(crowdsaleAddress)
    .then(([
             tokenAddress,
             walletAddress,
             startsAt,
             endsAt,
             updatable,
             isWhitelisted,
             maximumSellableTokens,
             pricingStrategyAddress,
             isFinalized,
             name,
             whitelistAccounts
           ]) => {
      crowdsaleStore.setSelectedProperty('finalized', isFinalized)
      crowdsaleStore.setSelectedProperty('updatable', crowdsaleStore.selected.updatable || updatable)

      newTier.walletAddress = walletAddress
      newTier.startTime = formatDate(startsAt)
      newTier.endTime = formatDate(endsAt)
      newTier.updatable = updatable
      newTier.tier = name

      initialValues.updatable = newTier.updatable
      initialValues.index = crowdsaleNum
      initialValues.addresses = {
        pricingStrategyAddress,
        tokenAddress,
        crowdsaleAddress
      }

      if (crowdsaleNum === 0) {
        newTier.whitelistEnabled = isWhitelisted ? 'yes' : 'no'
      }

      return Promise.all([pricingStrategyAddress, maximumSellableTokens, whitelistAccounts, tokenData(tokenAddress)])
    })
    .then(([pricingStrategyAddress, maximumSellableTokens, whitelistAccounts, [tokenName, tokenSymbol, decimals]]) => {
      tokenStore.setProperty('name', tokenName)
      tokenStore.setProperty('ticker', tokenSymbol)
      tokenStore.setProperty('decimals', decimals)

      //total supply
      const tokenDecimals = !isNaN(decimals) ? decimals : 0
      const maxCapBeforeDecimals = toBigNumber(maximumSellableTokens).div(`1e${tokenDecimals}`)

      newTier.supply = maxCapBeforeDecimals ? maxCapBeforeDecimals.toFixed() : 0

      return Promise.all([whitelistAccounts, pricingStrategyData(pricingStrategyAddress)])
    })
    .then(([whitelistAccounts, rate]) => {
      const { decimals } = tokenStore
      const tokenDecimals = !isNaN(decimals) ? decimals : 0

      //price
      newTier.rate = toBigNumber(web3.utils.fromWei(toBigNumber(rate).toFixed(), 'ether'))
        .pow(-1)
        .decimalPlaces(0)
        .toFixed()

      tierStore.addTier(newTier, {
        tier: VALID,
        walletAddress: VALID,
        rate: VALID,
        supply: VALID,
        startTime: VALID,
        endTime: VALID,
        updatable: VALID
      })

      const whitelist = newTier.whitelist.slice()

      whitelistAccounts.forEach(({ addr, min, max }) => {
        min = parseInt(toFixed(min), 10) / 10 ** tokenDecimals
        max = parseInt(toFixed(max), 10) / 10 ** tokenDecimals

        whitelist.push({ addr, min, max, stored: true })
      })

      tierStore.setTierProperty(whitelist, 'whitelist', crowdsaleNum)
      tierStore.sortWhitelist(crowdsaleNum)

      if (initialValues.updatable) {
        initialValues.startTime = newTier.startTime
        initialValues.endTime = newTier.endTime
        initialValues.rate = newTier.rate
        initialValues.supply = newTier.supply
        initialValues.whitelist = whitelist
      }
      crowdsaleStore.addInitialTierValues(initialValues)
    })
}

export function getFieldsToUpdate(updatableTiers, tiers) {
  const keys = Object
    .keys(updatableTiers[0])
    .filter(key => key !== 'index' && key !== 'updatable' && key !== 'addresses')

  const toUpdate = updatableTiers
    .reduce((toUpdate, tier, index) => {
      keys.forEach(key => {
        const { addresses } = tier
        let newValue = tiers[tier.index][key]

        if (isObservableArray(newValue)) {
          newValue = newValue.filter(item => !item.stored)

          if (newValue.length) {
            toUpdate.push({ key, newValue, addresses })
          }

        } else if (newValue !== tier[key]) {
          toUpdate.push({ key, newValue, addresses, tier: index })
        }
      })
      return toUpdate
    }, [])
    .sort((item1, item2) => {
      if (item1.tier !== item2.tier) {
        return item2.tier - item1.tier
      }

      if (item1.key === 'startTime' && item2.key === 'endTime') {
        return 1
      }

      if (item1.key === 'endTime' && item2.key === 'startTime') {
        return -1
      }

      return 0
    })

  return toUpdate
}
<commit_msg>Retrieve reserved tokens info<commit_after>import { isObservableArray } from 'mobx'
import { attachToContract, sendTXToContract } from '../../utils/blockchainHelpers'
import {
  contractStore,
  crowdsaleStore,
  generalStore,
  reservedTokenStore,
  tierStore,
  tokenStore,
  web3Store
} from '../../stores'
import { TRUNC_TO_DECIMALS, VALIDATION_TYPES } from '../../utils/constants'
import { floorToDecimals, toFixed } from '../../utils/utils'
import { toBigNumber } from '../crowdsale/utils'

const { VALID } = VALIDATION_TYPES

const formatDate = timestamp => {
  const ten = i => (i < 10 ? '0' : '') + i
  const date = new Date(timestamp * 1000)
  const YYYY = date.getFullYear()
  const MM = ten(date.getMonth() + 1)
  const DD = ten(date.getDate())
  const HH = ten(date.getHours())
  const II = ten(date.getMinutes())

  return YYYY + '-' + MM + '-' + DD + 'T' + HH + ':' + II
}

export const updateTierAttribute = (attribute, value, addresses) => {
  const { decimals } = tokenStore
  let methods = {
    startTime: 'setStartsAt',
    endTime: 'setEndsAt',
    supply: 'setMaximumSellableTokens',
    rate: 'updateRate',
    whitelist: 'setEarlyParticipantWhitelistMultiple'
  }
  let abi
  let contractAddresses

  if (attribute === 'startTime' || attribute === 'endTime' || attribute === 'supply' || attribute === 'whitelist') {
    abi = contractStore.crowdsale.abi
    contractAddresses = [addresses.crowdsaleAddress]

    if (attribute === 'startTime' || attribute === 'endTime') {
      value = [toFixed(parseInt(Date.parse(value) / 1000, 10).toString())]
    } else if (attribute === 'supply') {
      value = [toBigNumber(value).times(`1e${tokenStore.decimals}`).toFixed()]
    } else {
      // whitelist
      value = value.reduce((toAdd, whitelist) => {
        toAdd[0].push(whitelist.addr)
        toAdd[1].push(true)
        toAdd[2].push(whitelist.min * 10 ** decimals ? toFixed((whitelist.min * 10 ** decimals).toString()) : 0)
        toAdd[3].push(whitelist.max * 10 ** decimals ? toFixed((whitelist.max * 10 ** decimals).toString()) : 0)
        return toAdd
      }, [[], [], [], []])
    }
  }

  if (attribute === 'rate') {
    abi = contractStore.crowdsale.abi
    contractAddresses = [addresses.crowdsaleAddress]
    const oneTokenInETH = floorToDecimals(TRUNC_TO_DECIMALS.DECIMALS18, 1 / Number(value))
    value = [web3Store.web3.utils.toWei(oneTokenInETH, 'ether')]
  }

  if (!contractAddresses) return Promise.reject('no updatable value')

  if (attribute === 'whitelist') {
    const totalTiers = tierStore.tiers.length
    const currentTierIndex = crowdsaleStore.selected.initialTiersValues
      .findIndex(tier => tier.addresses.crowdsaleAddress === addresses.crowdsaleAddress)

    if (currentTierIndex <= totalTiers - 1) {
      contractAddresses = crowdsaleStore.selected.initialTiersValues
        .slice(currentTierIndex)
        .map(tier => tier.addresses.crowdsaleAddress)
    }
  }

  return contractAddresses.reduce((promise, contractAddress) => {
    return promise.then(() => {
      return attachToContract(abi, contractAddress)
        .then(contract => {
          const method = contract.methods[methods[attribute]]

          return method(...value).estimateGas()
            .then(estimatedGas => {
              return sendTXToContract(method(...value)
                .send({
                  gasLimit: estimatedGas,
                  gasPrice: generalStore.gasPrice
                })
              )
            })
        })
    })
  }, Promise.resolve())
}

const extractWhitelistInformation = (isWhitelisted, crowdsaleMethods) => {
  let whitelistedAccounts = []
  const whenWhitelistedAddresses = []

  if (isWhitelisted && crowdsaleMethods.whitelistedParticipantsLength) {
    return crowdsaleMethods.whitelistedParticipantsLength().call()
      .then(participantsCount => {
        for (let participantIndex = 0; participantIndex < participantsCount; participantIndex++) {
          whenWhitelistedAddresses.push(crowdsaleMethods.whitelistedParticipants(participantIndex).call())
        }

        return Promise.all(whenWhitelistedAddresses)
      })
      .then(whitelistedAddresses => {
        const whenAccountData = whitelistedAddresses
          .map(address => crowdsaleMethods.earlyParticipantWhitelist(address).call())

        return Promise.all(whenAccountData)
          .then(accountData => [isWhitelisted, whitelistedAddresses, accountData])
      })
  }

  return Promise.resolve([isWhitelisted, whenWhitelistedAddresses, whitelistedAccounts])
}

const crowdsaleData = crowdsaleAddress => {
  return attachToContract(contractStore.crowdsale.abi, crowdsaleAddress)
    .then(crowdsaleContract => {
      const { methods } = crowdsaleContract
      const whenToken = methods.token().call()
      const whenMultisigWallet = methods.multisigWallet().call()
      const whenStartsAt = methods.startsAt().call()
      const whenEndsAt = methods.endsAt().call()
      const whenIsUpdatable = methods.isUpdatable().call()
      const whenIsWhitelisted = methods.isWhiteListed().call()
      const whenMaximumSellableTokens = methods.maximumSellableTokens().call()
      const whenPricingStrategy = methods.pricingStrategy().call()
      const whenIsFinalized = methods.finalized().call()
      const whenName = methods.name().call()

      return whenIsWhitelisted
        .then(isWhitelisted => extractWhitelistInformation(isWhitelisted, methods))
        .then(([whitelisted, whitelistedAddresses, accountData]) => {
          const whitelistedAccounts = accountData.map((data, index) => {
            return {
              addr: whitelistedAddresses[index],
              min: data.minCap,
              max: data.maxCap
            }
          })

          return Promise.all([whitelisted, whitelistedAccounts])
        })
        .then(([isWhitelisted, whitelistAccounts]) => {
          return Promise.all([
            whenToken,
            whenMultisigWallet,
            whenStartsAt,
            whenEndsAt,
            whenIsUpdatable,
            isWhitelisted,
            whenMaximumSellableTokens,
            whenPricingStrategy,
            whenIsFinalized,
            whenName,
            whitelistAccounts
          ])
        })
    })
}

const parseReservedTokenValue = (value, decimals) => toBigNumber(value).div(`1e${decimals}`).toFixed()

const buildReservedTokenInfo = ([tokensInfo, addresses, decimals]) => addresses.map((address, index) => {
  const info = { addr: address }
  const tokenInfo = tokensInfo[index]

  if (tokenInfo.inTokens !== '0') {
    info.dim = 'tokens'
    info.val = parseReservedTokenValue(tokenInfo.inTokens, decimals)
    return info
  }

  info.dim = 'percentage'
  info.val = parseReservedTokenValue(tokenInfo.inPercentageUnit, tokenInfo.inPercentageDecimals)
  return info
})

const getReservedTokensData = (methods, length, decimals) => {
  const whenReservedTokensAddresses = []

  for (let i = 0; i < length; i++) {
    whenReservedTokensAddresses.push(methods.reservedTokensDestinations(i).call())
  }

  return Promise
    .all(whenReservedTokensAddresses)
    .then((addresses) => Promise.all(addresses.map(address => methods.reservedTokensList(address).call())))
    .then((reservedTokensInfo) => Promise.all([reservedTokensInfo, Promise.all(whenReservedTokensAddresses), decimals]))
    .then(buildReservedTokenInfo)
}

const tokenData = tokenAddress => {
  return attachToContract(contractStore.token.abi, tokenAddress)
    .then(tokenContract => {
      const { methods } = tokenContract
      const whenName = methods.name().call()
      const whenSymbol = methods.symbol().call()
      const whenDecimals = methods.decimals().call()
      const whenReservedTokensInfo = Promise
        .all([methods.reservedTokensDestinationsLen().call(), whenDecimals])
        .then(([length, decimals]) => getReservedTokensData(methods, length, decimals))

      return Promise.all([whenName, whenSymbol, whenDecimals, whenReservedTokensInfo])
    })
}

const pricingStrategyData = pricingStrategyAddress => {
  return attachToContract(contractStore.pricingStrategy.abi, pricingStrategyAddress)
    .then(pricingStrategyContract => pricingStrategyContract.methods.oneTokenInWei().call())
}

export const getTiers = crowdsaleAddress => {
  return attachToContract(contractStore.crowdsale.abi, crowdsaleAddress)
    .then(crowdsaleContract => {
      const { methods } = crowdsaleContract

      return methods.joinedCrowdsalesLen().call()
        .then(joinedCrowdsalesLen => {
          let joinedCrowdsales = []

          for (let joinedTierIndex = 0; joinedTierIndex < joinedCrowdsalesLen; joinedTierIndex++) {
            joinedCrowdsales.push(methods.joinedCrowdsales(joinedTierIndex).call())
          }

          return Promise.all(joinedCrowdsales)
        })
    })
}

export const processTier = (crowdsaleAddress, crowdsaleNum) => {
  const { web3 } = web3Store

  const newTier = {
    whitelist: []
  }

  const initialValues = {}

  return crowdsaleData(crowdsaleAddress)
    .then(([
             tokenAddress,
             walletAddress,
             startsAt,
             endsAt,
             updatable,
             isWhitelisted,
             maximumSellableTokens,
             pricingStrategyAddress,
             isFinalized,
             name,
             whitelistAccounts
           ]) => {
      crowdsaleStore.setSelectedProperty('finalized', isFinalized)
      crowdsaleStore.setSelectedProperty('updatable', crowdsaleStore.selected.updatable || updatable)

      newTier.walletAddress = walletAddress
      newTier.startTime = formatDate(startsAt)
      newTier.endTime = formatDate(endsAt)
      newTier.updatable = updatable
      newTier.tier = name

      initialValues.updatable = newTier.updatable
      initialValues.index = crowdsaleNum
      initialValues.addresses = {
        pricingStrategyAddress,
        tokenAddress,
        crowdsaleAddress
      }

      if (crowdsaleNum === 0) {
        newTier.whitelistEnabled = isWhitelisted ? 'yes' : 'no'
      }

      return Promise.all([pricingStrategyAddress, maximumSellableTokens, whitelistAccounts, tokenData(tokenAddress)])
    })
    .then(([
      pricingStrategyAddress,
      maximumSellableTokens,
      whitelistAccounts,
      [tokenName, tokenSymbol, decimals, reservedTokensInfo]
    ]) => {
      tokenStore.setProperty('name', tokenName)
      tokenStore.setProperty('ticker', tokenSymbol)
      tokenStore.setProperty('decimals', decimals)
      reservedTokensInfo.forEach((reservedTokenInfo) => reservedTokenStore.addToken(reservedTokenInfo))

      //total supply
      const tokenDecimals = !isNaN(decimals) ? decimals : 0
      const maxCapBeforeDecimals = toBigNumber(maximumSellableTokens).div(`1e${tokenDecimals}`)

      newTier.supply = maxCapBeforeDecimals ? maxCapBeforeDecimals.toFixed() : 0

      return Promise.all([whitelistAccounts, pricingStrategyData(pricingStrategyAddress)])
    })
    .then(([whitelistAccounts, rate]) => {
      const { decimals } = tokenStore
      const tokenDecimals = !isNaN(decimals) ? decimals : 0

      //price
      newTier.rate = toBigNumber(web3.utils.fromWei(toBigNumber(rate).toFixed(), 'ether'))
        .pow(-1)
        .decimalPlaces(0)
        .toFixed()

      tierStore.addTier(newTier, {
        tier: VALID,
        walletAddress: VALID,
        rate: VALID,
        supply: VALID,
        startTime: VALID,
        endTime: VALID,
        updatable: VALID
      })

      const whitelist = newTier.whitelist.slice()

      whitelistAccounts.forEach(({ addr, min, max }) => {
        min = parseInt(toFixed(min), 10) / 10 ** tokenDecimals
        max = parseInt(toFixed(max), 10) / 10 ** tokenDecimals

        whitelist.push({ addr, min, max, stored: true })
      })

      tierStore.setTierProperty(whitelist, 'whitelist', crowdsaleNum)
      tierStore.sortWhitelist(crowdsaleNum)

      if (initialValues.updatable) {
        initialValues.startTime = newTier.startTime
        initialValues.endTime = newTier.endTime
        initialValues.rate = newTier.rate
        initialValues.supply = newTier.supply
        initialValues.whitelist = whitelist
      }
      crowdsaleStore.addInitialTierValues(initialValues)
    })
}

export function getFieldsToUpdate(updatableTiers, tiers) {
  const keys = Object
    .keys(updatableTiers[0])
    .filter(key => key !== 'index' && key !== 'updatable' && key !== 'addresses')

  const toUpdate = updatableTiers
    .reduce((toUpdate, tier, index) => {
      keys.forEach(key => {
        const { addresses } = tier
        let newValue = tiers[tier.index][key]

        if (isObservableArray(newValue)) {
          newValue = newValue.filter(item => !item.stored)

          if (newValue.length) {
            toUpdate.push({ key, newValue, addresses })
          }

        } else if (newValue !== tier[key]) {
          toUpdate.push({ key, newValue, addresses, tier: index })
        }
      })
      return toUpdate
    }, [])
    .sort((item1, item2) => {
      if (item1.tier !== item2.tier) {
        return item2.tier - item1.tier
      }

      if (item1.key === 'startTime' && item2.key === 'endTime') {
        return 1
      }

      if (item1.key === 'endTime' && item2.key === 'startTime') {
        return -1
      }

      return 0
    })

  return toUpdate
}
<|endoftext|>


<commit_before>'use strict';

const m = require('mithril');
const get = require('lodash/get');

const collapsablePanel = require('./collapsable-panel');

module.exports = function routeParams (route) {
  return [
    paramsTable(route.validate, 'header'),
    paramsTable(route.validate, 'query'),
    paramsTable(route.validate, 'params'),
    paramsTable(route.validate, 'body'),
    ...outputTable(route.validate)
  ];
};

function outputTable (validations) {
  if (!validations || !validations.hasOwnProperty('output')) return [];
  const ret = [];
  Object.keys(validations.output).forEach(status => {
    if (validations.output[status].body) ret.push(paramsTable(validations, 'output', 'body', status));
    if (validations.output[status].header) ret.push(paramsTable(validations, 'output', 'header', status));
  });
  return ret;
}

function paramsTable (validations, type, label, status) {
  if (!validations || !validations.hasOwnProperty(type)) return [];

  let schema = validations[type];

  if (label && status) {
    schema = schema[status][label];
  }

  const heading = paramsHeader(schema, type, validations, label, status);

  const table = {
    style: { marginBottom: 0 }
  };

  const panel = {
    className: type === 'output' ? 'panel-primary' : ''
  };

  return collapsablePanel(heading, panel, [
    m('table.table.table-striped', table, [
      m.trust(`
            <colgroup>
               <col span="1" style="width: 15%;">
               <col span="1" style="width: 30%;">
               <col span="1" style="width: 15%;">
               <col span="1" style="width: 40%;">
            </colgroup>
         `),

      getItems(schema).map(paramsTableBody)
    ])
  ]);
}

function paramsHeader (schema, type, validations, outputLabel, status) {
  const bodyType = validations.type;
  const label = isArray(schema) ? arrayLabel(schema) : itemLabel(schema);

  const header = [
    type.slice(0, 1).toUpperCase() + type.slice(1),
    outputLabel ? `[${outputLabel}]` : '',
    !label ? '' : `: ${label}`
  ];

  // In case of body also indicate what type of body is expected
  // i.e. json, form, multipart
  if (type === 'body') {
    const tag = { style: { float: 'right' } };
    const bodyTag = m('span.label.label-info', tag, bodyType);
    header.push(bodyTag);
  } else if (type === 'output') {
    const outputTag = m('span.label.label-info', { style: { float: 'left', marginRight: '10px' } }, status);
    header.push(outputTag);
  }

  return header;
}

function paramsTableBody (schema) {
  const body = m('tbody');

  // TODO: sort validations by required

  body.children = traversingSchema(schema);

  body.children.unshift(m('tr', [
    m('th', 'Key = default'),
    m('th', 'Type* (tests) in [valids] not in [invalids]'),
    m('th', 'Eaxmples'),
    m('th', 'Description'),
  ]));

  return body;
}

function traversingSchema (schema, key) {
  const result = [];
  key && result.push(paramsRow(schema, key));
  if (schema.isJoi) {
    if (schema._type === 'object') {
      const children = get(schema, '_inner.children', []);
      children.forEach(child => {
        result.push(...traversingSchema(child.schema, key ? `${key}.${child.key}` : child.key));
      });
    } else if (schema._type === 'array') {
      const items = get(schema, '_inner.items', []);
      items.forEach(item => {
        result.push(...traversingSchema(item, `${key}[]`));
      });
    }
  } else if (typeof schema === 'object') {
    Object.keys(schema).forEach(k => {
      result.push(...traversingSchema(schema[k], key ? `${key}.${k}` : k));
    });
  } else {
    // schema is wrong
    throw new Error(`schema is invalid with key: ${key}, got ${JSON.stringify(schema)}`);
  }
  return result;
}

function paramsRow (schema, field) {
  const flags = schema._flags || {};
  const required = flags && flags.presence === 'required';
  const valids = schema._valids._set;
  const invalids = schema._invalids._set;
  const tests = schema._tests;
  return m('tr', [
    m('td', field + (flags.default ? ` = ${flags.default}` : '')),
    m('td', [
      schema._type,
      Array.isArray(schema) && 'array' || '',
      !required ? '' : ' *',
      tests.length > 0 ? ` [${tests.map(test => {
        return `${test.name}(${test.arg !== undefined ? test.arg : ''})`
      }).join(',')}]` : '',
      valids.toString() ? ` in [${valids}]` : '',
      invalids.toString() ? ` not in [${invalids}]` : ''
    ]),
    m('td', schema._examples.join(' | ')),
    m('td', schema._description || {}),
  ]);
}

function isArray (schema) {
  return schema._type === 'array';
}

function getItems (schema) {
  if (!isArray(schema)) return [schema];
  return get(schema, '_inner.items', []);
}

function itemLabel (schema) {
  const label = get(schema, '_settings.language.label', '');
  const type = schema._type || schema.constructor.name;
  const flags = schema._flags || {};
  return label || ((type.slice(0, 1).toUpperCase() + type.slice(1)) + (flags.default ? ` = ${flags.default}` : ''));
}

function arrayLabel (schema) {
  if (!isArray(schema)) return '';
  const items = getItems(schema).map(itemLabel);
  return `Array [ ${items} ]`;
}
<commit_msg>🙄 fixed: when default(0) cannot track the value<commit_after>'use strict';

const m = require('mithril');
const get = require('lodash/get');

const collapsablePanel = require('./collapsable-panel');

module.exports = function routeParams (route) {
  return [
    paramsTable(route.validate, 'header'),
    paramsTable(route.validate, 'query'),
    paramsTable(route.validate, 'params'),
    paramsTable(route.validate, 'body'),
    ...outputTable(route.validate)
  ];
};

function outputTable (validations) {
  if (!validations || !validations.hasOwnProperty('output')) return [];
  const ret = [];
  Object.keys(validations.output).forEach(status => {
    if (validations.output[status].body) ret.push(paramsTable(validations, 'output', 'body', status));
    if (validations.output[status].header) ret.push(paramsTable(validations, 'output', 'header', status));
  });
  return ret;
}

function paramsTable (validations, type, label, status) {
  if (!validations || !validations.hasOwnProperty(type)) return [];

  let schema = validations[type];

  if (label && status) {
    schema = schema[status][label];
  }

  const heading = paramsHeader(schema, type, validations, label, status);

  const table = {
    style: { marginBottom: 0 }
  };

  const panel = {
    className: type === 'output' ? 'panel-primary' : ''
  };

  return collapsablePanel(heading, panel, [
    m('table.table.table-striped', table, [
      m.trust(`
            <colgroup>
               <col span="1" style="width: 15%;">
               <col span="1" style="width: 30%;">
               <col span="1" style="width: 15%;">
               <col span="1" style="width: 40%;">
            </colgroup>
         `),

      getItems(schema).map(paramsTableBody)
    ])
  ]);
}

function paramsHeader (schema, type, validations, outputLabel, status) {
  const bodyType = validations.type;
  const label = isArray(schema) ? arrayLabel(schema) : itemLabel(schema);

  const header = [
    type.slice(0, 1).toUpperCase() + type.slice(1),
    outputLabel ? `[${outputLabel}]` : '',
    !label ? '' : `: ${label}`
  ];

  // In case of body also indicate what type of body is expected
  // i.e. json, form, multipart
  if (type === 'body') {
    const tag = { style: { float: 'right' } };
    const bodyTag = m('span.label.label-info', tag, bodyType);
    header.push(bodyTag);
  } else if (type === 'output') {
    const outputTag = m('span.label.label-info', { style: { float: 'left', marginRight: '10px' } }, status);
    header.push(outputTag);
  }

  return header;
}

function paramsTableBody (schema) {
  const body = m('tbody');

  // TODO: sort validations by required

  body.children = traversingSchema(schema);

  body.children.unshift(m('tr', [
    m('th', 'Key = default'),
    m('th', 'Type* (tests) in [valids] not in [invalids]'),
    m('th', 'Eaxmples'),
    m('th', 'Description'),
  ]));

  return body;
}

function traversingSchema (schema, key) {
  const result = [];
  key && result.push(paramsRow(schema, key));
  if (schema.isJoi) {
    if (schema._type === 'object') {
      const children = get(schema, '_inner.children', []);
      children.forEach(child => {
        result.push(...traversingSchema(child.schema, key ? `${key}.${child.key}` : child.key));
      });
    } else if (schema._type === 'array') {
      const items = get(schema, '_inner.items', []);
      items.forEach(item => {
        result.push(...traversingSchema(item, `${key}[]`));
      });
    }
  } else if (typeof schema === 'object') {
    Object.keys(schema).forEach(k => {
      result.push(...traversingSchema(schema[k], key ? `${key}.${k}` : k));
    });
  } else {
    // schema is wrong
    throw new Error(`schema is invalid with key: ${key}, got ${JSON.stringify(schema)}`);
  }
  return result;
}

function paramsRow (schema, field) {
  const flags = schema._flags || {};
  const required = flags && flags.presence === 'required';
  const valids = schema._valids._set;
  const invalids = schema._invalids._set;
  const tests = schema._tests;
  return m('tr', [
    m('td', field + (flags.default !== undefined ? ` = ${flags.default}` : '')),
    m('td', [
      schema._type,
      Array.isArray(schema) && 'array' || '',
      !required ? '' : ' *',
      tests.length > 0 ? ` [${tests.map(test => {
        return `${test.name}(${test.arg !== undefined ? test.arg : ''})`
      }).join(',')}]` : '',
      valids.toString() ? ` in [${valids}]` : '',
      invalids.toString() ? ` not in [${invalids}]` : ''
    ]),
    m('td', schema._examples.join(' | ')),
    m('td', schema._description || {}),
  ]);
}

function isArray (schema) {
  return schema._type === 'array';
}

function getItems (schema) {
  if (!isArray(schema)) return [schema];
  return get(schema, '_inner.items', []);
}

function itemLabel (schema) {
  const label = get(schema, '_settings.language.label', '');
  const type = schema._type || schema.constructor.name;
  const flags = schema._flags || {};
  return label || ((type.slice(0, 1).toUpperCase() + type.slice(1)) + (flags.default ? ` = ${flags.default}` : ''));
}

function arrayLabel (schema) {
  if (!isArray(schema)) return '';
  const items = getItems(schema).map(itemLabel);
  return `Array [ ${items} ]`;
}
<|endoftext|>