import React, { Component } from 'react' import axios from 'axios' import { isBrowser } from 'react-device-detect' import { SemanticToastContainer, toast } from 'react-semantic-toasts' import 'react-semantic-toasts/styles/react-semantic-alert.css' import { Dropdown, Table, Segment, Button, Search, Pagination, Icon, Accordion, Input, Message, Form, Radio } from 'semantic-ui-react' import './AppMain.css' import { yearDropDownOptions } from '../../constants/years' import { roundDropDownOptions } from '../../constants/rounds' import { iitDropDownOptions, nitDropDownOptions } from '../../constants/institutes' import { iitProgramDropDownOptions, nitProgramDropDownOptions } from '../../constants/programs' import { durationDropDownOptions } from '../../constants/durations' import { iitDegreeDropDownOptions, nitDegreeDropDownOptions } from '../../constants/degrees' import { categoryDropDownOptions } from '../../constants/categories' import { poolDropDownOptions } from '../../constants/pools' import instructions from '../../constants/instructions' const initialState = { data: [], year: '2021', round_no: '6', institute_type: 'IIT', quota: '', count: 0, search: '', currPage: 1, clickedColumn: '', direction: null, ordering: '', activeIndexs: [-1, 0, 1], institute_short: '', program: '', duration: '', degree: '', category: '', pool: '', userrank: 0, userdelta: 0 } class AppMain extends Component { constructor (props) { super(props) this.state = initialState } componentDidMount () { axios .get('/items/', { params: { year: this.state.year, round_no: this.state.round_no, institute_type: this.state.institute_type } }) .then(response => this.setState({ data: response.data.results, count: response.data.count }) ) .catch(err => { toast({ type: 'error', title: 'Error in your browser', description: ( <ul style={{ margin: '0em', padding: '0em' }}> <li>Either clear your browser cache or</li> <li>Use incognito or different browser.</li> </ul> ), animation: 'fade up', icon: 'ban', time: 10000 }) }) } handleChange = (e, { name, value }) => { if (value === 'All') { value = '' } // Temporary hack. // Create a generic handle change to avoid code repetition in future if (name === 'year') { if (value === '2021') { this.setState({ round_no: '6' }) } else { this.setState({ round_no: '' }) } } var showToast = false if ( name === 'year' || name === 'institute_type' || name === 'quota' || name === 'round_no' ) { showToast = true } this.setState({ [name]: value }, () => { axios .get('/items/', { params: { year: this.state.year, round_no: this.state.round_no, institute_type: this.state.institute_type, quota: this.state.quota, search: this.state.search, ordering: this.state.ordering, institute_short: this.state.institute_short, program_name: this.state.program, program_duration: this.state.duration, degree_short: this.state.degree, category: this.state.category, pool: this.state.pool, closing_rank__gte: Number(this.state.userrank) + Number(this.state.userdelta) } }) .then(response => this.setState( { data: response.data.results, count: response.data.count, currPage: 1 }, () => { if (showToast) { var msg if (value === 'OS') { msg = 'OS Quota' } else if (value === 'HS') { msg = 'HS Quota' } else if (value === '') { msg = 'HS & OS Quota' } else { msg = value } if (name === 'round_no') { msg = 'Round ' + value } toast({ type: 'success', title: `Changed to ${msg}`, description: 'Please scroll down to see the table.', animation: 'fade up', icon: 'check circle', time: 3000 }) } } ) ) .catch(err => { toast({ type: 'error', title: 'Error occured', description: 'Please try again after sometime.', animation: 'fade up', icon: 'ban', time: 3000 }) }) }) } handlePageChange = (event, data) => { this.setState({ currPage: data['activePage'] }, () => { axios .get('/items/', { params: { year: this.state.year, round_no: this.state.round_no, institute_type: this.state.institute_type, quota: this.state.quota, page: this.state.currPage, ordering: this.state.ordering, search: this.state.search, institute_short: this.state.institute_short, program_name: this.state.program, program_duration: this.state.duration, degree_short: this.state.degree, category: this.state.category, pool: this.state.pool, closing_rank__gte: Number(this.state.userrank) + Number(this.state.userdelta) } }) .then(response => this.setState({ data: response.data.results, count: response.data.count }) ) }) } handleSort = currColumn => () => { if (currColumn !== this.state.clickedColumn) { this.setState( { clickedColumn: currColumn, direction: 'ascending', ordering: currColumn, currPage: 1 }, () => { axios .get('/items/', { params: { year: this.state.year, round_no: this.state.round_no, institute_type: this.state.institute_type, quota: this.state.quota, page: this.state.currPage, ordering: this.state.clickedColumn, search: this.state.search, institute_short: this.state.institute_short, program_name: this.state.program, program_duration: this.state.duration, degree_short: this.state.degree, category: this.state.category, pool: this.state.pool, closing_rank__gte: Number(this.state.userrank) + Number(this.state.userdelta) } }) .then(response => this.setState({ data: response.data.results, count: response.data.count }) ) } ) return } this.setState( { direction: this.state.direction === 'ascending' ? 'descending' : 'ascending', ordering: this.state.direction === 'ascending' ? '-' + currColumn : currColumn }, () => { axios .get('/items/', { params: { year: this.state.year, round_no: this.state.round_no, institute_type: this.state.institute_type, quota: this.state.quota, page: this.state.currPage, ordering: this.state.ordering, search: this.state.search, institute_short: this.state.institute_short, program_name: this.state.program, program_duration: this.state.duration, degree_short: this.state.degree, category: this.state.category, pool: this.state.pool, closing_rank__gte: Number(this.state.userrank) + Number(this.state.userdelta) } }) .then(response => this.setState({ data: response.data.results, count: response.data.count, clickedColumn: currColumn }) ) } ) } handleAccordian = (e, titleProps) => { const { index } = titleProps const { activeIndexs } = this.state const newIndex = activeIndexs const currentIndexPosition = activeIndexs.indexOf(index) if (currentIndexPosition > -1) { newIndex.splice(currentIndexPosition, 1) } else { newIndex.push(index) } this.setState({ activeIndexs: newIndex }) } handlePersonalFilter = e => { this.setState( { [e.target.name]: e.target.valueAsNumber || e.target.value }, () => { axios .get('/items/', { params: { year: this.state.year, round: this.state.round_no, institute_type: this.state.institute_type, quota: this.state.quota, search: this.state.search, institute_short: this.state.institute_short, program_name: this.state.program, program_duration: this.state.duration, degree_short: this.state.degree, category: this.state.category, pool: this.state.pool, closing_rank__gte: Number(this.state.userrank) + Number(this.state.userdelta), ordering: 'opening_rank' } }) .then(response => this.setState({ data: response.data.results, count: response.data.count, currPage: 1 }) ) } ) } handleResetFilters = () => { this.setState(initialState, () => { axios .get('/items/', { params: { year: this.state.year, round_no: this.state.round_no, institute_type: this.state.institute_type } }) .then(response => this.setState({ data: response.data.results, count: response.data.count }) ) }) } render () { const { data, year, round_no, institute_type, quota, currPage, count, search, clickedColumn, direction, activeIndexs, institute_short, program, duration, degree, category, pool, userrank, userdelta } = this.state return ( <div className='app-main' id='scroll-to-filter'> <Segment> <div className='primary-filters-margin'> <div className='year-type'> <div className={ isBrowser ? 'year-round-browser' : 'year-round-mobile' } > <div> <Button content='Year' color='facebook' className='year-button' /> <Dropdown name='year' value={year} placeholder='All' selection compact options={yearDropDownOptions} onChange={this.handleChange} /> </div> {year === '2021' && ( <div> <Button className={ isBrowser ? 'round-button-browser' : 'round-button-mobile' } content='Round' color='facebook' /> <Dropdown name='round_no' value={round_no} placeholder='Round no' selection compact options={roundDropDownOptions} onChange={this.handleChange} /> </div> )} </div> <div className='year-type-margin'> <Form> <Form.Group className='form-group-margin-bottom'> <Form.Field> <Button content='College' color='facebook' /> </Form.Field> <Form.Field> <Radio className='college-margin' label='IIT' name='institute_type' value='IIT' checked={institute_type === 'IIT'} onChange={this.handleChange} /> </Form.Field> <Form.Field> <Radio className='college-margin' label='NIT' name='institute_type' value='NIT' checked={institute_type === 'NIT'} onChange={this.handleChange} /> </Form.Field> </Form.Group> </Form> </div> {institute_type === 'NIT' && ( <div className='year-type-margin'> <Form> <Form.Group className='form-group-margin-bottom'> <Form.Field> <Button content='State' color='facebook' className='state-button' /> </Form.Field> <Form.Field> <Radio className='college-margin' label='HS' name='quota' value='HS' checked={quota === 'HS'} onChange={this.handleChange} /> </Form.Field> <Form.Field> <Radio className='college-margin' label='OS' name='quota' value='OS' checked={quota === 'OS'} onChange={this.handleChange} /> </Form.Field> <Form.Field> <Radio className='college-margin' label='Both' name='quota' value='All' checked={quota === ''} onChange={this.handleChange} /> </Form.Field> </Form.Group> </Form> </div> )} </div> <SemanticToastContainer /> </div> <div className='year-note'> To all the future JEE aspirants, Best of Luck! :)) </div> </Segment> <Accordion fluid styled> <Accordion.Title active={activeIndexs.includes(-1)} index={-1} onClick={this.handleAccordian} > <Icon name='dropdown' /> Instructions </Accordion.Title> <Accordion.Content active={activeIndexs.includes(-1)}> <Message info list={instructions} /> </Accordion.Content> <Accordion.Title active={activeIndexs.includes(0)} index={0} onClick={this.handleAccordian} > <Icon name='dropdown' /> Primary Filters </Accordion.Title> <Accordion.Content active={activeIndexs.includes(0)}> <div className={isBrowser ? 'secondary-filters' : null}> <div className={isBrowser ? 'secondary-filters-col' : null}> <div className='secondary-filters-margin'> <Button content='Institute' color='facebook' /> <Dropdown className='dropdown-filters' name='institute_short' value={institute_short} placeholder='All' selection search clearable options={ this.state.institute_type === 'IIT' ? iitDropDownOptions : nitDropDownOptions } onChange={this.handleChange} /> </div> <div className='secondary-filters-margin'> <Button content='Program' color='facebook' /> <Dropdown className='dropdown-filters' name='program' value={program} placeholder='All' selection search clearable options={ this.state.institute_type === 'IIT' ? iitProgramDropDownOptions : nitProgramDropDownOptions } onChange={this.handleChange} /> </div> </div> <div className={isBrowser ? 'secondary-filters-col' : null}> <div className='secondary-filters-margin'> <Button content='Degree' color='facebook' /> <Dropdown className='dropdown-filters' name='degree' value={degree} placeholder='All' selection search clearable options={ this.state.institute_type === 'IIT' ? iitDegreeDropDownOptions : nitDegreeDropDownOptions } onChange={this.handleChange} /> </div> <div className='secondary-filters-margin'> <Button content='Duration' color='facebook' /> <Dropdown className='dropdown-filters' name='duration' value={duration} placeholder='All' selection search clearable options={durationDropDownOptions} onChange={this.handleChange} /> </div> </div> <div className={isBrowser ? 'secondary-filters-col' : null}> <div className='secondary-filters-margin'> <Button content='Pool' color='facebook' /> <Dropdown className='dropdown-filters' name='pool' value={pool} placeholder='All' selection search clearable options={poolDropDownOptions} onChange={this.handleChange} /> </div> <div className='secondary-filters-margin'> <Button content='Category' color='facebook' /> <Dropdown className='dropdown-filters' name='category' value={category} placeholder='All' selection search clearable options={categoryDropDownOptions} onChange={this.handleChange} /> </div> </div> </div> </Accordion.Content> <Accordion.Title active={activeIndexs.includes(1)} index={1} onClick={this.handleAccordian} > <Icon name='dropdown' /> Personal Rank based search </Accordion.Title> <Accordion.Content active={activeIndexs.includes(1)}> <div className='personalized-filter'> <div className='personlized-filter-align'> <Button content={ institute_type === 'IIT' ? 'Adv. Rank' : 'Mains Rank' } color='blue' /> <Input style={{ width: 130, height: 37 }} type='number' name='userrank' value={userrank} onChange={this.handlePersonalFilter} placeholder='Enter your JEE Rank' /> </div> <div className='personlized-filter-align'> <Button content='Delta' color='blue' /> <Input style={{ width: 130, height: 37 }} type='number' name='userdelta' value={userdelta} onChange={this.handlePersonalFilter} placeholder='Enter prefered Delta' /> </div> </div> </Accordion.Content> </Accordion> <div className='reset-margin'> <Button color='google plus' onClick={this.handleResetFilters}> Reset Filters </Button> </div> <div> <div className='global-search'> <Search name='search' value={search} placeholder='Search by any keyword' open={false} fluid onSearchChange={this.handleChange} /> </div> </div> <div className='table-overflow table-margin' id='scroll-ref'> <Table celled color={'blue'} sortable unstackable> <Table.Header> <Table.Row> <Table.HeaderCell textAlign='center'>Sr.</Table.HeaderCell> <Table.HeaderCell textAlign='center'>Year</Table.HeaderCell> {year === '2021' && ( <Table.HeaderCell textAlign='center'>Round</Table.HeaderCell> )} <Table.HeaderCell sorted={ clickedColumn === 'institute_short' ? direction : null } onClick={this.handleSort('institute_short')} textAlign='center' > Institute </Table.HeaderCell> <Table.HeaderCell sorted={clickedColumn === 'program_name' ? direction : null} onClick={this.handleSort('program_name')} textAlign='center' > Program </Table.HeaderCell> {institute_type === 'NIT' && ( <Table.HeaderCell textAlign='center'>Quota</Table.HeaderCell> )} <Table.HeaderCell sorted={ clickedColumn === 'program_duration' ? direction : null } onClick={this.handleSort('program_duration')} textAlign='center' > Duration </Table.HeaderCell> <Table.HeaderCell sorted={clickedColumn === 'degree_short' ? direction : null} onClick={this.handleSort('degree_short')} textAlign='center' > Degree </Table.HeaderCell> <Table.HeaderCell sorted={clickedColumn === 'category' ? direction : null} onClick={this.handleSort('category')} textAlign='center' > Category </Table.HeaderCell> <Table.HeaderCell sorted={clickedColumn === 'pool' ? direction : null} onClick={this.handleSort('pool')} textAlign='center' > Pool </Table.HeaderCell> <Table.HeaderCell sorted={clickedColumn === 'opening_rank' ? direction : null} onClick={this.handleSort('opening_rank')} textAlign='center' > Opening </Table.HeaderCell> <Table.HeaderCell sorted={clickedColumn === 'closing_rank' ? direction : null} onClick={this.handleSort('closing_rank')} textAlign='center' > Closing </Table.HeaderCell> </Table.Row> </Table.Header> <Table.Body> {data.map(element => ( <Table.Row key={data.indexOf(element)}> <Table.Cell collapsing textAlign='center'> {data.indexOf(element) + 1 + 50 * (currPage - 1)} </Table.Cell> <Table.Cell collapsing textAlign='center'> {element.year} </Table.Cell> {year === '2021' && ( <Table.Cell collapsing textAlign='center'> {element.round_no} </Table.Cell> )} <Table.Cell textAlign='center'> {element.institute_short} </Table.Cell> <Table.Cell textAlign='center'> {element.program_name} </Table.Cell> {institute_type === 'NIT' && ( <Table.Cell collapsing textAlign='center'> {element.quota} </Table.Cell> )} <Table.Cell collapsing textAlign='center'> {element.program_duration} </Table.Cell> <Table.Cell textAlign='center'> {element.degree_short} </Table.Cell> <Table.Cell collapsing textAlign='center'> {element.category} </Table.Cell> <Table.Cell textAlign='center'>{element.pool}</Table.Cell> <Table.Cell textAlign='center'> {element.is_preparatory ? element.opening_rank + ' - P' : element.opening_rank} </Table.Cell> <Table.Cell textAlign='center'> {element.is_preparatory ? element.closing_rank + ' - P' : element.closing_rank} </Table.Cell> </Table.Row> ))} </Table.Body> <Table.Footer> <Table.Row> <Table.HeaderCell colSpan='10'> <Pagination activePage={currPage} totalPages={data ? Math.ceil(count / 50) : '1'} onClick={() => document.getElementById('scroll-ref').scrollIntoView() } onPageChange={this.handlePageChange} firstItem={{ 'aria-label': 'First item', content: <Icon name='angle double left' />, key: '1' }} prevItem={{ 'aria-label': 'Previous item', content: <Icon name='angle left' />, key: '4' }} nextItem={{ 'aria-label': 'Next item', content: <Icon name='angle right' />, key: '3' }} lastItem={{ 'aria-label': 'Last item', content: <Icon name='angle double right' />, key: '2' }} /> </Table.HeaderCell> </Table.Row> </Table.Footer> </Table> <Icon className='scroll-to-top' name='chevron circle up' size='big' color='grey' onClick={() => { document.getElementById('scroll-to-filter').scrollIntoView() }} /> </div> <div className='github-repo'> *This is an open source project, if found helpful, do star{' '} <a href='https://github.com/nisarg73/jee-dashboard' target='_blank' rel='noopener noreferrer' > its github repo </a>{' '} :D </div> </div> ) } } export default AppMain