diff --git a/.gitignore b/.gitignore index 67d19a5..eaedbce 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ /pmp-frontend-app/npm-debug.log* pmp-frontend-app/public/.DS_Store + +/react-app \ No newline at end of file diff --git a/pmp-frontend-app/package-lock.json b/pmp-frontend-app/package-lock.json index 91fc783..6dd1349 100644 --- a/pmp-frontend-app/package-lock.json +++ b/pmp-frontend-app/package-lock.json @@ -9,8 +9,10 @@ "version": "0.0.0", "dependencies": { "@jonkoops/matomo-tracker-react": "^0.7.0", + "axios": "^1.6.8", "daisyui": "^4.7.3", "js-cookie": "^3.0.5", + "lato-font": "^3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-google-recaptcha": "^3.1.0", @@ -1719,6 +1721,11 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.18", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", @@ -1756,6 +1763,16 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -1980,6 +1997,17 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -2109,6 +2137,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -2655,6 +2691,25 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -2671,6 +2726,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -3174,6 +3242,11 @@ "json-buffer": "3.0.1" } }, + "node_modules/lato-font": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lato-font/-/lato-font-3.0.0.tgz", + "integrity": "sha512-wKhFCh9XX91Lepf38ynnZTNpkQD1OWuXV1RwFgcchUVQZzBixJ/yXCaVCIrNI3CbgT9pLcLzWKgn+6OETzAnug==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4084,6 +4157,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -4557,6 +4649,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/pmp-frontend-app/package.json b/pmp-frontend-app/package.json index b1a8540..3c00cbf 100644 --- a/pmp-frontend-app/package.json +++ b/pmp-frontend-app/package.json @@ -11,8 +11,10 @@ }, "dependencies": { "@jonkoops/matomo-tracker-react": "^0.7.0", + "axios": "^1.6.8", "daisyui": "^4.7.3", "js-cookie": "^3.0.5", + "lato-font": "^3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-google-recaptcha": "^3.1.0", diff --git a/pmp-frontend-app/src/components/DataSourcesComponent.tsx b/pmp-frontend-app/src/components/DataSourcesComponent.tsx new file mode 100644 index 0000000..395cd7c --- /dev/null +++ b/pmp-frontend-app/src/components/DataSourcesComponent.tsx @@ -0,0 +1,232 @@ +import { ReactElement, useState } from "react"; +import React from "react"; +import axios from 'axios'; +import { IDataSourceFilters, IDataSourcesDC } from "../interfaces/types"; + +export default function DataSourcesComponent(): ReactElement { + const [dataSourcesJSON, setDataSourcesJSON] = useState([]); + const [selectedFilters, setSelectedFilters] = useState({ + dataTypes: [], + diseaseTypes: [], + }); + const [searchBar, setSearchBar] = useState(""); + + const filters: IDataSourceFilters = { + dataTypes: + [ + "Biobank", + "Chemical Biology", + "Clinical", + "Enzymes, Pathways, Interactions", + "Epidemiology", + "Evolution and Phylogeny", + "General", + "Genes and Genomes", + "Imaging", + "Molecular and Cellular Structures", + "Phenotypic", + "Proteins and Proteomes", + ], + diseaseTypes: + [ + "Cancer", + "Cardiovascular Diseases", + "Neurological Disorders", + "Genetic Disorders", + "Metabolic Disorders", + "Infectious Diseases", + "Developmental Disorders", + "Rare Diseases", + "Drug Development", + "Public Health", + "Immunological Diseases", + "Psychiatric Disorders", + "General", + "Various Diseases", + ], + }; + + const nrOfCheckboxes = (filters.dataTypes.concat(filters.diseaseTypes).length); + const checkedListBoolArr = Array.apply(null, Array(nrOfCheckboxes)).map(function () { return false }); + + const [checkedList, setCheckedList] = useState(checkedListBoolArr); + + // const dataSourcesURI: string = 'https://raw.githubusercontent.com/ScilifelabDataCentre/data.scilifelab.se/main/data/data_sources.json'; + const dataSourcesURI: string = 'https://raw.githubusercontent.com/SevLG/data.scilifelab.se/patch-1/data/data_sources.json'; + + async function getData(){ + setDataSourcesJSON([]); + const tmpDataSourcesJSON: IDataSourcesDC[] = [] + let responseData: IDataSourcesDC[] = []; + await axios.get(dataSourcesURI) + .then(response => { + responseData = response.data; + }) + .catch(response => console.log(response.error)) + + responseData.forEach( (element: IDataSourcesDC) => { + if (element.ddls.includes('Precision Medicine and Diagnostics')) { + tmpDataSourcesJSON.push(element); + } + }); + setDataSourcesJSON(tmpDataSourcesJSON); + } + + function checkedDataFilter(tagType: string, tagName: string, boxIndex: number) { + let tmpFilters = selectedFilters; + let tmpCheckedList = [...checkedList]; + + switch (tagType) { + case "dataType": + if (tmpFilters.dataTypes.includes(tagName)) { + tmpFilters.dataTypes = tmpFilters.dataTypes.filter(item => item != tagName); + tmpCheckedList[boxIndex] = false; + } else { + tmpFilters.dataTypes.push(tagName); + tmpCheckedList[boxIndex] = true; + } + break; + case "diseaseType": + if (tmpFilters.diseaseTypes.includes(tagName)) { + tmpFilters.diseaseTypes = tmpFilters.diseaseTypes.filter(item => item != tagName); + tmpCheckedList[boxIndex] = false; + } else { + tmpFilters.diseaseTypes.push(tagName); + tmpCheckedList[boxIndex] = true; + } + break; + } + + + setSelectedFilters(tmpFilters); + setCheckedList(tmpCheckedList); + } + + function applyDataTypeFilter(dataSource: IDataSourcesDC) { + if (selectedFilters.dataTypes.length === 0) { + return true; + } else { + let filter: string; + for (filter of selectedFilters.dataTypes) { + if (!dataSource.data.map(tag => tag.toLowerCase()).includes(filter.toLowerCase())) { + return false; + } + } + return true; + } + } + + function applyDiseaseTypeFilter(dataSource: IDataSourcesDC) { + if (selectedFilters.diseaseTypes.length === 0) { + return true; + } else { + let filter: string; + for (filter of selectedFilters.diseaseTypes) { + if (!dataSource.disease_type.map(tag => tag.toLowerCase()).includes(filter.toLowerCase())) { + return false; + } + } + return true; + } + } + + function applySearchBar(dataSource: IDataSourcesDC) { + const searchBarLower = searchBar.toLowerCase(); + const searchTags: string[] = searchBarLower.split(" "); + if (searchBarLower.length === 0) { + return true; + } else { + if (dataSource.name.toLowerCase().includes(searchBarLower)) { + return true; + } else { + let searchTag: string; + for (searchTag of searchTags) { + if (dataSource.search_tags.map(tag => tag.toLowerCase()).includes(searchTag) || + dataSource.search_tags.map(tag => tag.toLowerCase()).includes(searchBarLower)) { + return true; + } + } + return false; + } + } + } + + function RenderDataSources(): ReactElement { + return ( +
+ {dataSourcesJSON + .filter(data => applyDataTypeFilter(data)) + .filter(data => applyDiseaseTypeFilter(data)) + .filter(data => applySearchBar(data)) + .map((item, index) => ( +
+
+ {item.name} +

IMG_PLACEHOLDER

+
+

{item.description}

+
+ ))} +
+ ); + } + + React.useEffect(() =>{ + getData(); + }, []); + + return ( + <> +
+
+
+ + setSearchBar(e.target.value)} + /> +
+
+

Data Type

+
+ {filters.dataTypes.map((element, index) => +
+ + {element} +
+ )} +
+

Disease Type

+
+ {filters.diseaseTypes.map((element, index) => +
+ + {element} +
+ )} +
+
+
+ +
+ + ); +} \ No newline at end of file diff --git a/pmp-frontend-app/src/components/HeaderComponent.tsx b/pmp-frontend-app/src/components/HeaderComponent.tsx index 07a8c43..4c4af0c 100644 --- a/pmp-frontend-app/src/components/HeaderComponent.tsx +++ b/pmp-frontend-app/src/components/HeaderComponent.tsx @@ -69,7 +69,7 @@ export default function HeaderComponent() {
    {Object.keys(links).map( key => ( -
  • {{links[key].text}}
  • +
  • {{links[key].text}}
  • ))}
diff --git a/pmp-frontend-app/src/components/ImageCarouselComponent.tsx b/pmp-frontend-app/src/components/ImageCarouselComponent.tsx index 81bd7e3..1ae9c2d 100644 --- a/pmp-frontend-app/src/components/ImageCarouselComponent.tsx +++ b/pmp-frontend-app/src/components/ImageCarouselComponent.tsx @@ -12,18 +12,6 @@ export default function ImageCarouselComponent(): ReactElement {
Pizza
-
- Pizza -
-
- Pizza -
-
- Pizza -
-
- Pizza -
); } \ No newline at end of file diff --git a/pmp-frontend-app/src/constants.ts b/pmp-frontend-app/src/constants.ts index 2d03112..4830b86 100644 --- a/pmp-frontend-app/src/constants.ts +++ b/pmp-frontend-app/src/constants.ts @@ -4,6 +4,6 @@ export const H_1: string = "text-left text-black text-[40px] font-semibold"; export const BUTTON_TYPE_ONE: string = 'btn bg-fuchsia-950 text-white hover:bg-fuchsia-800 active:bg-fuchsia-900 focus:outline-none focus:ring focus:ring-fuchsia-300'; export const BUTTON_TYPE_TWO: string = 'btn bg-gray-950 text-white hover:bg-gray-800 active:bg-gray-900 focus:outline-none focus:ring focus:ring-gray-300'; -export const BODY_CLASSES: string = "bg-base-100 space-y-8 py-4 px-36 pb-60 2xl:max-w-screen-2xl 2xl:mx-auto"; +export const BODY_CLASSES: string = "bg-base-100 space-y-8 py-4 px-36 pb-28 2xl:max-w-screen-2xl 2xl:mx-auto"; export const LINK_CLASSES: string = 'link link-hover'; \ No newline at end of file diff --git a/pmp-frontend-app/src/content/content.ts b/pmp-frontend-app/src/content/content.ts index a82614c..c1ddfa5 100644 --- a/pmp-frontend-app/src/content/content.ts +++ b/pmp-frontend-app/src/content/content.ts @@ -185,7 +185,7 @@ export const TeamDescriptions = { } export const DataSourcesPageContent = { - textBar: 'This page is currently under construction. Please check back later for updates.', + textBar: 'Repositories and Data Sources in Precision Medicine', } export const EventsAndTrainingsPageContent = { diff --git a/pmp-frontend-app/src/index.css b/pmp-frontend-app/src/index.css index bd6213e..d867668 100644 --- a/pmp-frontend-app/src/index.css +++ b/pmp-frontend-app/src/index.css @@ -1,3 +1,9 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +@layer base { + html { + font-family: Lato, sans-serif + } +} \ No newline at end of file diff --git a/pmp-frontend-app/src/interfaces/types.ts b/pmp-frontend-app/src/interfaces/types.ts index 476a93c..6615882 100644 --- a/pmp-frontend-app/src/interfaces/types.ts +++ b/pmp-frontend-app/src/interfaces/types.ts @@ -31,4 +31,23 @@ export interface ICardContent { buttonText: string; imageSrc: string; imageAlt: string; +}; + +export interface IDataSourceFilters { + dataTypes: string[]; + diseaseTypes: string[]; +}; + +export interface IDataSourcesDC { + data: string[]; + ddls: string[]; + description: string; + name: string; + search_tags: string[]; + target: string[]; + thumbnail: string; + thumbnail_border?: boolean; + type: string[]; + url: string; + disease_type: string[] }; \ No newline at end of file diff --git a/pmp-frontend-app/src/pages/DataSourcesPage.tsx b/pmp-frontend-app/src/pages/DataSourcesPage.tsx index 300a41e..35ad7b5 100644 --- a/pmp-frontend-app/src/pages/DataSourcesPage.tsx +++ b/pmp-frontend-app/src/pages/DataSourcesPage.tsx @@ -1,12 +1,14 @@ import { ReactElement } from 'react'; import { TrackPageViewIfEnabled } from '../util/cookiesHandling'; +import DataSourcesComponent from '../components/DataSourcesComponent'; +import { BODY_CLASSES } from '../constants'; export default function DataPage(): ReactElement { TrackPageViewIfEnabled(); return ( -
-

Data page under construction

+
+
); } \ No newline at end of file diff --git a/pmp-frontend-app/src/pages/HomePage.tsx b/pmp-frontend-app/src/pages/HomePage.tsx index 73fb8b7..62ee830 100644 --- a/pmp-frontend-app/src/pages/HomePage.tsx +++ b/pmp-frontend-app/src/pages/HomePage.tsx @@ -1,6 +1,6 @@ import { ReactElement } from 'react'; import CardComponent from "../components/CardComponent"; -import ImageCarouselComponent from "../components/ImageCarouselComponent"; +import ImageCarouselAlternativeComponent from "../components/ImageCarouselAlternativeComponent"; import { BODY_CLASSES, BUTTON_TYPE_ONE, H_1} from '../constants'; import { ICardConfig, ICardContent } from '../interfaces/types'; import { TrackPageViewIfEnabled } from '../util/cookiesHandling'; @@ -55,7 +55,9 @@ export default function HomePage(): ReactElement { return (
- + + { + /* Commented out until the team has sufficient time to fill the cards with useful content

Latest News

@@ -74,6 +76,8 @@ export default function HomePage(): ReactElement {
+ */ +}
);