diff --git a/src/components/JobSearch.js b/src/components/JobSearch.js new file mode 100644 index 0000000..3608d25 --- /dev/null +++ b/src/components/JobSearch.js @@ -0,0 +1,174 @@ +import React from "react"; +import styled from "styled-components"; + +import { Button, FocusBoundary, Form, Link, Offer } from "@components"; +import { toQueryString } from "@utils/toQueryString"; + +const ResultsFooter = styled.div` + margin: 8rem 2rem; + text-align: center; + + @media (min-width: 600px) { + margin: 8rem; + } + + > button { + margin: 0; + } +`; + +const LOADING = "LOADING"; +const SUCCESS = "SUCCESS"; +const ERROR = "ERROR"; + +const fields = [ + { + name: "type", + type: "select", + defaultValue: "hiring", + options: [ + { value: "hiring", label: "I'm looking for a job" }, + { value: "for-hire", label: "I'm looking for an employee" }, + ], + }, + { + name: "range", + type: "select", + defaultValue: "180", + options: [ + { value: "7", label: "offers posted in last week" }, + { value: "30", label: "offers posted in last 30 days" }, + { value: "90", label: "offers posted in last 3 months" }, + { value: "180", label: "offers posted in last 6 months" }, + { value: "365", label: "offers posted in last year" }, + ], + }, + { + name: "limit", + type: "select", + defaultValue: "50", + options: [ + { value: "50", label: "load 50 results at a time" }, + { value: "100", label: "load 100 results at a time" }, + ], + }, + { + name: "query", + type: "text", + placeholder: "Text search", + }, + { + label: "Employer helps with visa", + name: "provideVisa", + type: "checkbox", + defaultValue: false, + }, + { + label: "Accepts remote candidates", + name: "allowRemote", + type: "checkbox", + defaultValue: false, + }, + { + label: "Offer is an internship / no exp. required", + name: "internship", + type: "checkbox", + defaultValue: false, + }, +]; + +const JobSearch = ({ toggleModal, setSidebar }) => { + const debounceTimer = React.useRef(); + const [state, setState] = React.useState({}); + const { limit, next, results = [], status = LOADING, url } = state; + + const onChangeQuery = React.useCallback( + (query) => { + setState((_state) => ({ + ..._state, + clearResults: true, + limit: parseInt(query.limit, 10), + url: `https://reactistory.com:8443/api/job?${toQueryString(query)}`, + })); + }, + [setState], + ); + + const onClickNext = () => + setState((_state) => ({ + ..._state, + next: undefined, + status: LOADING, + url: _state.next, + })); + + React.useEffect(() => { + if (url) { + clearTimeout(debounceTimer.current); + + debounceTimer.current = setTimeout(() => { + setState((_state) => ({ + ..._state, + clearResults: undefined, + results: _state.clearResults ? [] : _state.results, + status: LOADING, + })); + + fetch(url) + .then((res) => res.json()) + .then((data) => { + setState((_state) => ({ + ..._state, + status: SUCCESS, + results: _state.results.concat(data.messages), + next: + data.messages.length === limit + ? `https://reactistory.com:8443${data.paginate.prev}` + : undefined, + })); + }) + .catch(() => { + setState((_state) => ({ ..._state, status: ERROR })); + }); + }, 400); + } + }, [limit, url]); + + return ( + <> + +
+ +
+ {results.map((result, i) => ( + + ))} + + {status === LOADING ? ( +

Fetching posts...

+ ) : next ? ( + + ) : null} + {status === ERROR ? ( +

+ Something went wrong - please try again! If this problem persists, + please let us know. +

+ ) : status === SUCCESS && results.length === 0 ? ( +

+ We couldn’t find any results for your query - try something + different! +

+ ) : null} +
+
+ + ); +}; + +export default JobSearch; diff --git a/src/pages/jobs.js b/src/pages/jobs.js index edfbfa2..140653a 100644 --- a/src/pages/jobs.js +++ b/src/pages/jobs.js @@ -1,149 +1,14 @@ import React from "react"; -import styled from "styled-components"; -import { - Button, - FocusBoundary, - Form, - Layout, - Link, - Modal, - Offer, -} from "@components"; -import { toQueryString } from "@utils/toQueryString"; +import { DiscordAuth } from "@components/DiscordAuth"; -const ResultsFooter = styled.div` - margin: 8rem 2rem; - text-align: center; - - @media (min-width: 600px) { - margin: 8rem; - } - - > button { - margin: 0; - } -`; - -const LOADING = "LOADING"; -const SUCCESS = "SUCCESS"; -const ERROR = "ERROR"; - -const fields = [ - { - name: "type", - type: "select", - defaultValue: "hiring", - options: [ - { value: "hiring", label: "I'm looking for a job" }, - { value: "for-hire", label: "I'm looking for an employee" }, - ], - }, - { - name: "range", - type: "select", - defaultValue: "180", - options: [ - { value: "7", label: "offers posted in last week" }, - { value: "30", label: "offers posted in last 30 days" }, - { value: "90", label: "offers posted in last 3 months" }, - { value: "180", label: "offers posted in last 6 months" }, - { value: "365", label: "offers posted in last year" }, - ], - }, - { - name: "limit", - type: "select", - defaultValue: "50", - options: [ - { value: "50", label: "load 50 results at a time" }, - { value: "100", label: "load 100 results at a time" }, - ], - }, - { - name: "query", - type: "text", - placeholder: "Text search", - }, - { - label: "Employer helps with visa", - name: "provideVisa", - type: "checkbox", - defaultValue: false, - }, - { - label: "Accepts remote candidates", - name: "allowRemote", - type: "checkbox", - defaultValue: false, - }, - { - label: "Offer is an internship / no exp. required", - name: "internship", - type: "checkbox", - defaultValue: false, - }, -]; +import { Layout, Link, Modal } from "@components"; +import JobSearch from "../components/JobSearch"; const Jobs = () => { - const debounceTimer = React.useRef(); - const [state, setState] = React.useState({}); - const { limit, next, results = [], status = LOADING, url } = state; const [showModal, setModal] = React.useState(false); const toggleModal = () => setModal((prev) => !prev); - const onChangeQuery = React.useCallback( - (query) => { - setState((_state) => ({ - ..._state, - clearResults: true, - limit: parseInt(query.limit, 10), - url: `https://reactistory.com:8443/api/job?${toQueryString(query)}`, - })); - }, - [setState], - ); - - const onClickNext = () => - setState((_state) => ({ - ..._state, - next: undefined, - status: LOADING, - url: _state.next, - })); - - React.useEffect(() => { - if (url) { - clearTimeout(debounceTimer.current); - - debounceTimer.current = setTimeout(() => { - setState((_state) => ({ - ..._state, - clearResults: undefined, - results: _state.clearResults ? [] : _state.results, - status: LOADING, - })); - - fetch(url) - .then((res) => res.json()) - .then((data) => { - setState((_state) => ({ - ..._state, - status: SUCCESS, - results: _state.results.concat(data.messages), - next: - data.messages.length === limit - ? `https://reactistory.com:8443${data.paginate.prev}` - : undefined, - })); - }) - .catch(() => { - setState((_state) => ({ ..._state, status: ERROR })); - }); - }, 400); - } - }, [limit, url]); - return ( {(setSidebar) => ( @@ -151,41 +16,9 @@ const Jobs = () => {

Reactiflux Jobs

- - - -
- {results.map((result, i) => ( - - ))} - - {status === LOADING ? ( -

Fetching posts...

- ) : next ? ( - - ) : null} - {status === ERROR ? ( -

- Something went wrong - please try again! If this problem - persists, please let us know. -

- ) : status === SUCCESS && results.length === 0 ? ( -

- We couldn’t find any results for your query - try something - different! -

- ) : null} -
-
+ + + setModal(false)} isOpen={showModal}>

If the job post does not contain a dedicated email, link, or phone