| "csstype": "^3.0.2" | "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": { | "dom-serializer": { | ||||
| "version": "0.2.2", | "version": "0.2.2", | ||||
| "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", | ||||
| "whatwg-fetch": "^3.4.1" | "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": { | "react-dev-utils": { | ||||
| "version": "11.0.4", | "version": "11.0.4", | ||||
| "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", | "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", |
| "lodash.isempty": "^4.4.0", | "lodash.isempty": "^4.4.0", | ||||
| "owasp-password-strength-test": "^1.3.0", | "owasp-password-strength-test": "^1.3.0", | ||||
| "react": "^17.0.2", | "react": "^17.0.2", | ||||
| "react-autocomplete": "^1.8.1", | |||||
| "react-dom": "^17.0.2", | "react-dom": "^17.0.2", | ||||
| "react-helmet-async": "^1.0.9", | "react-helmet-async": "^1.0.9", | ||||
| "react-i18next": "^11.10.0", | "react-i18next": "^11.10.0", |
| import history from './store/utils/history'; | import history from './store/utils/history'; | ||||
| //import Header from './components/Header/Header'; | //import Header from './components/Header/Header'; | ||||
| import "react-responsive-carousel/lib/styles/carousel.min.css"; | import "react-responsive-carousel/lib/styles/carousel.min.css"; | ||||
| // import Header from './components/Header/Header'; | |||||
| // import Sidebar from './components/Sidebar/Sidebar'; | // import Sidebar from './components/Sidebar/Sidebar'; | ||||
| import AppRoutes from './AppRoutes'; | import AppRoutes from './AppRoutes'; | ||||
| </> | </> | ||||
| </Router> | </Router> | ||||
| ); | |||||
| ); | |||||
| export default App; | export default App; |
| $base-font-size: 16px; | $base-font-size: 16px; | ||||
| $base-font-size-md: 14px; | $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 | // Colors | ||||
| $color-primary: #024f86; | $color-primary: #024f86; |
| import React, { useState } from 'react'; | import React, { useState } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | |||||
| import Select from 'react-select' | import Select from 'react-select' | ||||
| import { prices, beds, types, lifeStyles } from '../../constants/filters'; | import { prices, beds, types, lifeStyles } from '../../constants/filters'; | ||||
| import './CreateScrapeRequest.scss' | import './CreateScrapeRequest.scss' | ||||
| import PropTypes from 'prop-types'; | 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 CreateScrapeRequest = ({ handleRequest }) => { | ||||
| const { t } = useTranslation(); | |||||
| const [requestObject, setRequestObject] = useState({ location: '' }) | const [requestObject, setRequestObject] = useState({ location: '' }) | ||||
| const { t } = useTranslation(); | |||||
| const handleChangePriceType = async selectedOption => { | const handleChangePriceType = async selectedOption => { | ||||
| setRequestObject(s => ({ ...s, price: selectedOption.value })) | setRequestObject(s => ({ ...s, price: selectedOption.value })) | ||||
| console.log("requestObject", requestObject) | console.log("requestObject", requestObject) | ||||
| return ( | return ( | ||||
| <div className="card card-primary"> | <div className="card card-primary"> | ||||
| <div className="card-header"> | |||||
| <h3 className="card-title">{t('createScrapeRequest.Title')}</h3> | |||||
| </div> | |||||
| <form > | <form > | ||||
| <div className="card-body"> | <div className="card-body"> | ||||
| <div className="row"> | <div className="row"> | ||||
| <div className="col-md-3"> | |||||
| {/* <div className="col-md-3"> | |||||
| <div className="form-group"> | <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 }))} /> | <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> */} | |||||
| <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> | ||||
| <div className="col-md-2"> | <div className="col-md-2"> | ||||
| <div className="form-group"> | <div className="form-group"> |
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| console.log("id", id) | console.log("id", id) | ||||
| if (status === 'requested') | 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') | else if (status === 'done') | ||||
| return <span className='badge bg-success'>Done</span> | |||||
| return <span className='badge bg-success text-lg'>Done</span> | |||||
| else | else | ||||
| return <span className='badge bg-warning'>Pending</span> | |||||
| return <span className='badge bg-danger text-lg'>Pending</span> | |||||
| } | } | ||||
| return ( | return ( | ||||
| <div className="card"> | <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> : | {scrappes.length === 0 ? <tbody><tr><td><span className='center-align'>Nothing to show</span></td></tr></tbody> : | ||||
| <div className="card-body p-0"> | <div className="card-body p-0"> | ||||
| <table className="table table-sm"> | <table className="table table-sm"> | ||||
| <thead> | <thead> | ||||
| <tr> | <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> | </tr> | ||||
| </thead> | </thead> | ||||
| <tbody> | <tbody> |
| import CreateScrapeRequest from '../../components/CreateScrapeRequest/CreateScrapeRequest'; | import CreateScrapeRequest from '../../components/CreateScrapeRequest/CreateScrapeRequest'; | ||||
| import ScrapeRequests from '../../components/ScrapeRequests/ScrapeRequests'; | import ScrapeRequests from '../../components/ScrapeRequests/ScrapeRequests'; | ||||
| import { createScrappes, executeScrappes, getAllScrappes } from '../../request/scrappe'; | import { createScrappes, executeScrappes, getAllScrappes } from '../../request/scrappe'; | ||||
| import { useTranslation } from 'react-i18next'; | |||||
| const HomePage = () => { | const HomePage = () => { | ||||
| const [scrappes, setScrappes] = useState([]) | const [scrappes, setScrappes] = useState([]) | ||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getAllScrappes().then(res => setScrappes(res.data)) | getAllScrappes().then(res => setScrappes(res.data)) | ||||
| const interval = setInterval(() => { | const interval = setInterval(() => { | ||||
| return ( | 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} /> | <CreateScrapeRequest handleRequest={handleRequest} /> | ||||
| <ScrapeRequests scrappes={scrappes} handleExecute={handleExecute} /> | <ScrapeRequests scrappes={scrappes} handleExecute={handleExecute} /> | ||||
| </> | </> |
| return ( | 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} /> | <ScrappeDetails details = {scrappeDetails} /> | ||||
| <div className ='content' > | <div className ='content' > | ||||
| <div className="container"> | <div className="container"> |