Commit 2fd363b6 authored by Nitin Jadhav's avatar Nitin Jadhav
Browse files

Merge branch 'content-pages' into 'master'

Some bugfixes, readme update

See merge request !42
parents fbe2b6fe 968cf132
Pipeline #157251 passed with stages
in 4 minutes and 57 seconds
{
"env": {
"node":true,
"browser": true,
"es2021": true,
"jest": true
"env": {
"node": true,
"browser": true,
"es2021": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:prettier/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:prettier/recommended"
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["react"],
"rules": {
"prettier/prettier": [
"warn",
{
"endOfLine": "auto"
}
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"prettier/prettier": "warn",
"no-unused-vars": "warn",
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react/no-unescaped-entities":"off",
"no-debugger":"warn"
}
}
\ No newline at end of file
"no-unused-vars": "warn",
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react/no-unescaped-entities": "off",
"no-debugger": "warn"
}
}
# vf-react
# EMBL-Jobs (embl-jobs-pages)
A React boilerplate for VF 2.0 projects.
A React-based project for EMBL jobs functionality
Demo: https://visual-framework.github.io/vf-react/
Production link: https://www.embl.org/jobs/#
Development link: https://wwwdev.embl.org/jobs/#
Notes:
- Based on [VF-React](https://visual-framework.github.io/vf-react/#/)
- If you add a Visual Framework component, be sure to include it at `src/vf-components/vf-componenet-rollup/index.scss`
- Add custom CSS to `src/vf-components/vf-local-overrides/vf-local-overrides.scss`
- Bootstrapped with [Create React App](https://github.com/facebook/create-react-app), that brings certain advantages and limitations. If you want to escape those, read up on "[eject](https://create-react-app.dev/docs/available-scripts#npm-run-eject)"
- Uses [Create React App](https://github.com/facebook/create-react-app), that brings certain advantages and limitations. If you want to escape those, read up on "[eject](https://create-react-app.dev/docs/available-scripts#npm-run-eject)"
Watchout for:
- Use `yarn` and not `npm`
- This is still in early development
- The building of VF component assets (CSS, JS, images, etc.) from `.vf-components` into `./build/vf-generated-assets` does not seem to be working after [#25](https://github.com/visual-framework/vf-react/pull/25)
- Gulp may eventually removed from this project
- We're still coming up with an approach on how to handle the use of VF JS inside React (probably we'll import the VF JS modules directly)
- Use react components from VF-Core as much as possible
## Available scripts
......@@ -42,27 +41,6 @@ Launches the test runner in the interactive watch mode.<br>
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
# embl-jobs-pages
Creates pages for `embl.org/jobs/position/{name}`
- Made with `vf-eleventy`
- Pulls jobs from contentHub via `https://www.embl.org/api/v1/jobs?_format=json&source=contenthub`
- Redirects from email alerts using format of https://www.embl.org/jobs/alerts/alert-email/{nPostingTargetID}(3656)
- Redirects from EMBL.de are mostly handled by the script at https://sourcecode.embl.de/webdev/website/nps-legacy/-/blob/master/js/ext/src/embl_jobs_redirect.js (as of Feb 2021)
## Developing
1. You'll need to [install npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
1. If you don't have `yarn`, install it
- https://yarnpkg.com/lang/en/docs/install/
1. Install all the things
- `yarn install`
1. Generate the site in `/build`
- `gulp dev` renders and serves
- `gulp build` build static assets
### Local setup using docker
1. Run `docker-compose up` this will generate image & build the application locally
......
......@@ -7,6 +7,7 @@ import { Partners } from "components/content/Partners";
import { JobDetails } from "components/job-details/JobDetails";
import { Metadata } from "components/Metadata";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { ErrorPage404 } from "../component-templates/ErrorPages/ErrorPage404";
import { HrExcellenceInResearch } from "../components/content/HrExcellenceInResearch";
import { Science4Refugees } from "../components/content/Science4Refugees";
import { ConditionsEmployment } from "../components/content/work-at-embl/conditions-employment/ConditionsEmployment";
......@@ -78,7 +79,7 @@ export function App() {
/>
{/* default route */}
<Route path="*" component={EMBLHome} />
<Route path="*" component={ErrorPage404} />
</Switch>
</div>
</Router>
......
import { VfIntro } from "../VFIntro";
export function ErrorPage404() {
return (
<>
<VfIntro
vf_intro_heading="Error: 404"
vf_intro_subheading=""
vf_intro_lede="We’re sorry - we can’t find the page or file you requested."
vf_intro_text={[
"It may have been removed, had its name changed, or be temporarily unavailable.",
"You might try <a href='https://www.embl.org/search'>searching for it</a>.",
]}
/>
<section className="embl-grid">
<div></div>
<div className="vf-content">
<h3>Need assistance?</h3>
<a
className="vf-button vf-button--primary"
href="https://www-db.embl.de/EMBLPersonGroup-PersonPicture/MailForm/?recipient=websupport"
>
Contact web support
</a>
</div>
</section>
</>
);
}
import { useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { debounce } from "lodash-es";
......@@ -6,6 +6,10 @@ export function VFSearchBox({ value, handleSearchTermUpdate }) {
const [term, setTerm] = useState("");
const handleDebouncedUpdate = useRef(debounce(handleSearchTermUpdate, 500));
useEffect(() => {
setTerm(value);
}, [value]);
return (
<form className="vf-form | vf-search vf-search--inline">
<div className="vf-container__inner" style={{ width: "100%" }}>
......
import React from "react";
import { memo } from "react";
export class EmblHeader extends React.Component {
render() {
return (
<link
rel="import"
href="https://www.embl.org/api/v1/pattern.html?filter-content-type=article&filter-id=108434&pattern=node-body&source=contenthub"
data-target="self"
data-embl-js-content-hub-loader
/>
);
}
}
export const EmblHeader = memo(function EmblHeader() {
return (
<link
rel="import"
href="https://www.embl.org/api/v1/pattern.html?filter-content-type=article&filter-id=108434&pattern=node-body&source=contenthub"
data-target="self"
data-embl-js-content-hub-loader
/>
);
});
import { Helmet } from "react-helmet";
import { VfIntro } from "../../component-templates/VFIntro";
import ContentMeta from "./components/ContentMeta";
import { EMBLContentTemplate } from "./components/EMBLContentTemplate";
......
......@@ -8,7 +8,11 @@ export function EBIHome() {
{/* Supports iframe resizing on ebi.ac.uk/careers/jobs */}
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
</Helmet>
<Home showLocations={false} jobLocation="EMBL-EBI Hinxton" isIframe="true" />
<Home
showLocations={false}
jobLocation="EMBL-EBI Hinxton"
isIframe="true"
/>
</>
);
}
import React from "react";
import { EmblCards } from "../EmblCards";
import { EmblHeader } from "../EmblHeader";
import { EmblBreadcrumbs } from "../EmblBreadcrumbs";
import { EmblCards } from "../EmblCards";
import { EmblFooter } from "../EmblFooter";
import "./Home.scss";
import { EmblHeader } from "../EmblHeader";
import { Home } from "./Home";
import "./Home.scss";
export function EMBLHome() {
return (
<React.Fragment>
<>
<EmblHeader />
<EmblBreadcrumbs />
......@@ -90,6 +89,6 @@ export function EMBLHome() {
<EmblCards />
<EmblFooter />
</React.Fragment>
</>
);
}
import { VFSearchBox } from "component-templates/VFSearchBox";
import {
getInitialFilters,
JobListFilters,
} from "components/job-list-filters/JobListFilters";
import { JobListFilters } from "components/job-list-filters/JobListFilters";
import { JobList } from "components/job-list/JobList";
import React, { useCallback, useState } from "react";
import React, { useState } from "react";
import { useFetchJobsList } from "services/useFetchJobsList";
import "./Home.scss";
export const getInitialFilters = () => ({
selectedLocations: [],
selectedJobTypes: [],
selectedClosingDateSortDir: "DESC",
searchTerm: "",
});
export function Home({ showLocations = true, jobLocation, isIframe = false }) {
const [filters, setFilters] = useState(getInitialFilters());
const resetFilters = () => {
setFilters(getInitialFilters());
};
const {
filteredJobs: jobs,
locationJobsCount,
......@@ -45,6 +53,7 @@ export function Home({ showLocations = true, jobLocation, isIframe = false }) {
</section>
<section className="embl-grid">
<JobListFilters
resetFilters={resetFilters}
filters={filters}
locationJobsCount={locationJobsCount}
positionJobsCount={positionJobsCount}
......@@ -53,7 +62,12 @@ export function Home({ showLocations = true, jobLocation, isIframe = false }) {
showLocations={showLocations}
/>
<JobList jobs={jobs} loading={loading} isIframe={isIframe} />
<JobList
jobs={jobs}
loading={loading}
isIframe={isIframe}
resetFilters={resetFilters}
/>
</section>
</>
)}
......
......@@ -16,6 +16,7 @@ import { EmblHeader } from "../EmblHeader";
import { EmblBreadcrumbs } from "../EmblBreadcrumbs";
import { EmblFooter } from "../EmblFooter";
import { EBICards } from "../EBICards";
import { VfIntro } from "../../component-templates/VFIntro";
const shortcutLinks = [
{
......@@ -101,7 +102,7 @@ export function JobDetails() {
}
if (!currentJob) {
return null;
return <JobNotFound />;
}
return (
......@@ -441,3 +442,27 @@ function renderWhyJoinUsVideo(jobType) {
</>
);
}
function JobNotFound() {
return (
<>
<VfIntro
vf_intro_heading="Job not found."
vf_intro_subheading=""
vf_intro_lede="This job may have been expired."
/>
<section className="embl-grid">
<div></div>
<div className="vf-content">
<a
className="vf-button vf-button--primary"
href="https://www.embl.org/jobs"
>
See all Jobs
</a>
</div>
</section>
</>
);
}
import React from "react";
import { VFLoaderBox } from "component-templates/VFLoader/VFLoader";
import { toggleInArray } from "helpers/helpers";
import "./JobListFilters.scss";
export const getInitialFilters = () => ({
selectedLocations: [],
selectedJobTypes: [],
selectedClosingDateSortDir: "DESC",
searchTerm: "",
});
export function JobListFilters({
filters,
locationJobsCount = [],
......@@ -17,6 +9,7 @@ export function JobListFilters({
onFiltersChange,
loading,
showLocations = true,
resetFilters,
}) {
const handleLocationFilterChange = (location) => {
// toggle this element in array
......@@ -50,7 +43,7 @@ export function JobListFilters({
const handleResetFilters = (event) => {
event.preventDefault();
onFiltersChange(getInitialFilters());
resetFilters();
};
if (loading) {
......
......@@ -5,7 +5,7 @@ import { formatISODate, parseISODateFromTimeHtml } from "helpers/date-helpers";
import { stripHtml } from "helpers/helpers";
import "./JobList.scss";
export function JobList({ jobs, loading, isIframe = false }) {
export function JobList({ jobs, loading, resetFilters, isIframe = false }) {
if (loading) {
return <VFLoaderBox />;
}
......@@ -15,7 +15,15 @@ export function JobList({ jobs, loading, isIframe = false }) {
{jobs.map((job) => (
<JobList.JobListItem key={job.id} job={job} isIframe={isIframe} />
))}
{!jobs.length && <p>No matching jobs found.</p>}
{!jobs.length && (
<p>
No matching jobs found;{" "}
<a href="#" onClick={resetFilters}>
Reset your filters
</a>
.
</p>
)}
<hr className="vf-divider" />
<p>
......@@ -35,7 +43,7 @@ JobList.JobListItem = function JobListItem({ job, isIframe = false }) {
<h3 className="job-title vf-summary__title">
<Link
to={`/position/${job.field_jobs_reference_number}`}
target={isIframe ? '_parent' : '_self' }
target={isIframe ? "_parent" : "_self"}
className="vf-summary__link"
>
{job.title}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment