| @@ -6017,6 +6017,11 @@ | |||
| "csstype": "^3.0.2" | |||
| } | |||
| }, | |||
| "dom-scroll-into-view": { | |||
| "version": "1.0.1", | |||
| "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-1.0.1.tgz", | |||
| "integrity": "sha1-Mqu5Lw2P7KYhUWKu9D5LRJq42Zw=" | |||
| }, | |||
| "dom-serializer": { | |||
| "version": "0.2.2", | |||
| "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", | |||
| @@ -13808,6 +13813,15 @@ | |||
| "whatwg-fetch": "^3.4.1" | |||
| } | |||
| }, | |||
| "react-autocomplete": { | |||
| "version": "1.8.1", | |||
| "resolved": "https://registry.npmjs.org/react-autocomplete/-/react-autocomplete-1.8.1.tgz", | |||
| "integrity": "sha1-67vEAABqqRrVOLLRRye55+XQYxA=", | |||
| "requires": { | |||
| "dom-scroll-into-view": "1.0.1", | |||
| "prop-types": "^15.5.10" | |||
| } | |||
| }, | |||
| "react-dev-utils": { | |||
| "version": "11.0.4", | |||
| "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", | |||
| @@ -19,6 +19,7 @@ | |||
| "lodash.isempty": "^4.4.0", | |||
| "owasp-password-strength-test": "^1.3.0", | |||
| "react": "^17.0.2", | |||
| "react-autocomplete": "^1.8.1", | |||
| "react-dom": "^17.0.2", | |||
| "react-helmet-async": "^1.0.9", | |||
| "react-i18next": "^11.10.0", | |||
| @@ -5,6 +5,7 @@ import i18next from 'i18next'; | |||
| import history from './store/utils/history'; | |||
| //import Header from './components/Header/Header'; | |||
| import "react-responsive-carousel/lib/styles/carousel.min.css"; | |||
| // import Header from './components/Header/Header'; | |||
| // import Sidebar from './components/Sidebar/Sidebar'; | |||
| import AppRoutes from './AppRoutes'; | |||
| @@ -23,6 +24,6 @@ const App = () => ( | |||
| </> | |||
| </Router> | |||
| ); | |||
| ); | |||
| export default App; | |||
| @@ -1,7 +1,7 @@ | |||
| $base-font-size: 16px; | |||
| $base-font-size-md: 14px; | |||
| $font-family: 'Avenir Next'; | |||
| $font-family: "Source Sans Pro",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; | |||
| // Colors | |||
| $color-primary: #024f86; | |||
| @@ -1,15 +1,22 @@ | |||
| import React, { useState } from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import Select from 'react-select' | |||
| import { prices, beds, types, lifeStyles } from '../../constants/filters'; | |||
| import './CreateScrapeRequest.scss' | |||
| import PropTypes from 'prop-types'; | |||
| import { states } from '../../constants/states' | |||
| import Autocomplete from 'react-autocomplete'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| export function matchStateToTerm(state, value) { | |||
| return ( | |||
| state.label.toLowerCase().indexOf(value.toLowerCase()) !== -1 | |||
| ) | |||
| } | |||
| const CreateScrapeRequest = ({ handleRequest }) => { | |||
| const { t } = useTranslation(); | |||
| const [requestObject, setRequestObject] = useState({ location: '' }) | |||
| const { t } = useTranslation(); | |||
| const handleChangePriceType = async selectedOption => { | |||
| setRequestObject(s => ({ ...s, price: selectedOption.value })) | |||
| @@ -28,16 +35,49 @@ const CreateScrapeRequest = ({ handleRequest }) => { | |||
| console.log("requestObject", requestObject) | |||
| return ( | |||
| <div className="card card-primary"> | |||
| <div className="card-header"> | |||
| <h3 className="card-title">{t('createScrapeRequest.Title')}</h3> | |||
| </div> | |||
| <form > | |||
| <div className="card-body"> | |||
| <div className="row"> | |||
| <div className="col-md-3"> | |||
| {/* <div className="col-md-3"> | |||
| <div className="form-group"> | |||
| <input type="text" className="form-control input-field cursor-pointer" value={requestObject.location} placeholder={t('createScrapeRequest.LocationPlaceholder')} onChange={e => setRequestObject(s => ({ ...s, location: e.target.value }))} /> | |||
| </div> | |||
| </div> */} | |||
| <div className="col-md-3"> | |||
| <div className="form-group"> | |||
| <Autocomplete | |||
| menuStyle={{ | |||
| padding: ".375rem .75rem", | |||
| fontSize: '1rem', | |||
| fontWeight: '400', | |||
| lineHeight: 1.5, | |||
| color: "#495057", | |||
| backgroundColor: '#fff', | |||
| backgroundClip: "padding-box", | |||
| border: "1px solid #ced4da", | |||
| borderRadius: ".25rem", | |||
| boxShadow: "inset 0 0 0 transparent", | |||
| transition: " border-color .15s ease-in-out,box-shadow .15s ease-in-out", | |||
| background: 'rgba(255, 255, 255, 0.9)', | |||
| position: 'fixed', | |||
| overflow: 'auto', | |||
| maxHeight: '50%', | |||
| zIndex: 2001 | |||
| }} | |||
| renderInput={(props) => <input {...props} type="text" className="form-control input-field cursor-pointer" placeholder={t('createScrapeRequest.LocationPlaceholder')} />} | |||
| getItemValue={(item) => item.label} | |||
| items={states.map(s => ({ label: s }))} | |||
| renderItem={(item, isHighlighted) => | |||
| <div style={{ background: isHighlighted ? 'lightgray' : 'white', }}> | |||
| {item.label} | |||
| </div> | |||
| } | |||
| shouldItemRender={matchStateToTerm} | |||
| value={requestObject.location} | |||
| onChange={(e, val) => setRequestObject(s => ({ ...s, location: val }))} | |||
| onSelect={(val) => setRequestObject(s => ({ ...s, location: val }))} | |||
| /> | |||
| </div> | |||
| </div> | |||
| <div className="col-md-2"> | |||
| <div className="form-group"> | |||
| @@ -7,11 +7,11 @@ const ScrappeStatus = ({ status, handleExecute, id }) => { | |||
| const { t } = useTranslation(); | |||
| console.log("id", id) | |||
| if (status === 'requested') | |||
| return <button type="submit" className="btn btn-xs btn-block btn-primary" onClick={() => handleExecute(id)}><i className="fa fa-bell" ></i>{t('common.execute')}</button> | |||
| return <button type="submit" className="btn btn-sm btn-block btn-primary" onClick={() => handleExecute(id)}><i className="fa fa-bell"></i>{t('common.execute')}</button> | |||
| else if (status === 'done') | |||
| return <span className='badge bg-success'>Done</span> | |||
| return <span className='badge bg-success text-lg'>Done</span> | |||
| else | |||
| return <span className='badge bg-warning'>Pending</span> | |||
| return <span className='badge bg-danger text-lg'>Pending</span> | |||
| } | |||
| @@ -10,17 +10,15 @@ const ScrapeRequests = ({ scrappes, handleExecute }) => { | |||
| return ( | |||
| <div className="card"> | |||
| <div className="card-header"> | |||
| <h3 className="card-title">{t('scrapeRequests.Title')}</h3> | |||
| </div> | |||
| {scrappes.length === 0 ? <tbody><tr><td><span className='center-align'>Nothing to show</span></td></tr></tbody> : | |||
| <div className="card-body p-0"> | |||
| <table className="table table-sm"> | |||
| <thead> | |||
| <tr> | |||
| <th className='font-weight-bold'>{t('scrapeRequests.Columns.Scrape')}</th> | |||
| <th>{t('scrapeRequests.Columns.Filters')}</th> | |||
| <th>{t('scrapeRequests.Columns.Status')}</th> | |||
| <th className='text-black-50 font-weight-bold'>{t('scrapeRequests.Columns.Scrape')}</th> | |||
| <th className='text-black-50 font-weight-bold'>{t('scrapeRequests.Columns.Filters')}</th> | |||
| <th className='text-black-50 font-weight-bold'>{t('scrapeRequests.Columns.Status')}</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| @@ -2,9 +2,11 @@ import React, { useEffect, useState } from 'react'; | |||
| import CreateScrapeRequest from '../../components/CreateScrapeRequest/CreateScrapeRequest'; | |||
| import ScrapeRequests from '../../components/ScrapeRequests/ScrapeRequests'; | |||
| import { createScrappes, executeScrappes, getAllScrappes } from '../../request/scrappe'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| const HomePage = () => { | |||
| const [scrappes, setScrappes] = useState([]) | |||
| const { t } = useTranslation(); | |||
| useEffect(() => { | |||
| getAllScrappes().then(res => setScrappes(res.data)) | |||
| const interval = setInterval(() => { | |||
| @@ -31,9 +33,10 @@ const HomePage = () => { | |||
| return ( | |||
| <> | |||
| <h1 className="lead text-center" >Scrapper </h1> | |||
| <h1 className="lead text-center" style={{ fontSize: '80px' }}>{t('scrapeRequests.Columns.Scrape')} </h1> | |||
| <hr></hr> | |||
| <h2 className="lead text-center text-muted" style={{ fontSize: '40px' }}>https://www.apartments.com/</h2> | |||
| <br></br> | |||
| <CreateScrapeRequest handleRequest={handleRequest} /> | |||
| <ScrapeRequests scrappes={scrappes} handleExecute={handleExecute} /> | |||
| </> | |||
| @@ -24,9 +24,15 @@ const ScrapeResultsPage = ({ location }) => { | |||
| return ( | |||
| <> | |||
| <Link to="/" className="navbar-brand"> | |||
| <span className="brand-text font-weight-light">Back</span> | |||
| </Link> | |||
| <nav className="main-header navbar navbar-expand-md navbar-light navbar-white"> | |||
| <div className="container"> | |||
| <Link to="/" className="navbar-brand"> | |||
| <span className="brand-text font-weight-light">Back to Scrape</span> | |||
| </Link> | |||
| </div> | |||
| </nav> | |||
| <ScrappeDetails details = {scrappeDetails} /> | |||
| <div className ='content' > | |||
| <div className="container"> | |||