first push

This commit is contained in:
louai98 2023-05-12 13:36:59 +02:00
parent 604982f150
commit 98b53a0432
28 changed files with 3149 additions and 245 deletions

2320
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,25 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.0",
"@react-pdf/renderer": "^3.1.9",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.4.0",
"bootstrap": "^5.2.3",
"d3": "^7.8.4",
"d3-cloud": "^1.2.5",
"file-saver": "^2.0.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.7.4",
"react-d3-cloud": "^1.0.6",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-scripts": "5.0.1", "react-pdf": "^6.2.2",
"react-scripts": "^5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {

View File

@ -1,24 +1,126 @@
import logo from './logo.svg'; import logo from "./logo.svg";
import './App.css'; import "./App.css";
import Search from "./Components/Layout/Search/Search";
import Filter from "./Components/Layout/Filter/Filter";
import ComplainceFilter from "./Components/Layout/Filter/ComplainceFilter";
import Results from "./Components/Layout/Results/Results";
import { Fragment, useState, useEffect } from "react";
import axios from "axios";
import FeaturedQuestions from "./Components/Layout/FeaturedQuestions/FeaturedQuestions";
import WordCloud_ from "./Components/Layout/WordCloud_/WordCloud_";
import Stack from "react-bootstrap/esm/Stack";
import Container from "react-bootstrap/esm/Container";
function App() { function App() {
const [data, setData] = useState("");
const [results, setResults] = useState([]);
const [filteredResults, setFilteredResults] = useState([]);
const [filtersComplaince, setFiltersComplaince] = useState([]);
const [filtersStandards, setFiltersStandards] = useState([]);
// the useEffect hook is used to apply filters whenever the results,
// filtersStandards, or filtersComplaince values change
useEffect(() => {
setFilteredResults(
applyFilters(results, filtersStandards, filtersComplaince)
);
}, [results, filtersStandards, filtersComplaince]);
//################################################################################
const handleSubmit = (event) => {
event.preventDefault();
// Send the input value to Django
axios
.post("http://localhost:8000/get_input/", { data })
.then((response) => {
setResults(response.data.results);
setFilteredResults(response.data.results);
})
.catch((error) => {
console.log(error);
});
};
const handleSubmit_ = (value) => {
// Send the input value to Django
axios
.post("http://localhost:8000/get_input/", { data: { phrase: value } })
.then((response) => {
setResults(response.data.results);
setFilteredResults(response.data.results);
})
.catch((error) => {
console.log(error);
});
};
//################################################################################
// function to apply multiple filters to the results in any order and ensure
// that each filter is applied to the recent filtered results
function applyFilters(results, filter1, filter2) {
let filteredResults__ = results;
// Apply the Standards filter if it is provided, Array#some method checks if at least one
// element in filter1 matches the result.Title value.
if (filter1.length > 0) {
console.log("filter1");
filteredResults__ = filteredResults__.filter((result) => {
return filter1.some((filter) => filter == result.Title);
});
}
// Apply the second filter if it is provided
if (filter2.length > 0) {
console.log("filter2");
filteredResults__ = filteredResults__.filter((result) => {
return filter2.every((filter) => result[filter]);
});
}
return filteredResults__;
}
//################################################################################
// apply the complaince check on the results and then send the new results to the
// results component
function handleComplainceFilterChange(ComplainceFilterValue) {
setFiltersComplaince(ComplainceFilterValue);
}
//################################################################################
// apply the standards filter on the results and then send the new results to the
// results component
function handleStandardsFilterChange(StandardsFilterValue) {
setFiltersStandards(StandardsFilterValue);
}
//################################################################################
// append the input to the data. The data will be sent later to the
// server side
const handleChange = (event) => {
setData({
...data,
[event.target.name]: event.target.value,
});
};
return ( return (
<div className="App"> <Fragment>
<header className="App-header"> <main>
<img src={logo} className="App-logo" alt="logo" /> <Container>
<p> <Search onSubmit={handleSubmit} onChange={handleChange} />
Edit <code>src/App.js</code> and save to reload. <Filter onFilterChange={handleStandardsFilterChange} />
</p> <ComplainceFilter onFilterChange={handleComplainceFilterChange} />
<a <Results results={filteredResults} />
className="App-link"
href="https://reactjs.org" <Stack direction="horizontal" gap={3} as="div" className="d-flex justify-content-between">
target="_blank" <FeaturedQuestions handleButtonClick={handleSubmit_} />
rel="noopener noreferrer" <WordCloud_ />
> </Stack>
Learn React </Container>
</a> </main>
</header> </Fragment>
</div>
); );
} }

View File

@ -0,0 +1,40 @@
import React, { useState } from "react";
import Container from "react-bootstrap/esm/Container";
import Stack from "react-bootstrap/esm/Stack";
import Card from "react-bootstrap/Card";
const FeaturedQuestions = ({ handleButtonClick }) => {
const handleClick = (value) => {
//console.log(event.target.value)
handleButtonClick(value);
};
const fqs = [
"What are DDR-related tools?",
"Who participates in a DDR process?",
"Which preconditions are required for the implementation of a viable DDR programme?",
"What is the difference between a DDR process and a DDR programme?",
"How can ex-combatants be best supported in their reintegration?",
];
return (
<div>
<Card className="p-3">
<h4 className="text-decoration-underline">
Featured Questions About IDDRS Framework
</h4>
<Stack gap={4}>
{fqs.map((fq) => (
<li key={fq}>
<a name="phrase" onClick={() => handleClick(fq)} value={fq}>
{fq}
</a>
</li>
))}
</Stack>
</Card>
</div>
);
};
export default FeaturedQuestions;

View File

@ -0,0 +1,44 @@
import { useState } from "react";
import ToggleButton from "react-bootstrap/ToggleButton";
import ToggleButtonGroup from "react-bootstrap/ToggleButtonGroup";
import Container from "react-bootstrap/esm/Container";
import classes from "./ComplainceFilter.module.css";
function ComplainceFilter({ onFilterChange }) {
const [value, setValue] = useState([]);
/*
* The second argument that will be passed to
* `handleChange` from `ToggleButtonGroup`
* is the SyntheticEvent object, but we are
* not using it in this example so we will omit it.
*/
const handleChange = (val) => {
//console.log(val);
setValue(val);
onFilterChange(val);
};
const complaince = ["Shall", "Should", "May", "Must", "Can"];
return (
<div className="mt-3">
<h5>Compliance Check:</h5>
<ToggleButtonGroup type="checkbox" value={value} onChange={handleChange}>
{complaince.map((comp, index) => (
<ToggleButton
type="checkbox"
variant="outline-secondary"
key={index}
id={`comp-btn-${index}`}
className={classes["comp-btn"]}
value={comp}
>
{comp}
</ToggleButton>
))}
</ToggleButtonGroup>
</div>
);
}
export default ComplainceFilter;

View File

@ -0,0 +1,59 @@
import React, { useEffect, useState } from "react";
import Dropdown_ from "../../UI/Dropdown/Dropdown_";
import Container from "react-bootstrap/Container";
import axios from "axios";
const Filter = ({ onFilterChange }) => {
const [levels, setLevels] = useState([]);
const [standards, setStandards] = useState([]);
const [standardsFilter, setStandardsFilter] = useState([]);
// get the filters values to this component
function handelOnFilterChange(newFilters){
setStandardsFilter(newFilters)
onFilterChange(newFilters)
//console.log(newFilters)
}
useEffect(() => {
axios
.get("http://127.0.0.1:8000/levels/")
.then((response) => setLevels(response.data))
.catch((error) => console.log(error));
}, []);
useEffect(() => {
axios
.get("http://127.0.0.1:8000/standards/")
.then((response) => setStandards(response.data))
.catch((error) => console.log(error));
}, []);
return (
<Container className="mt-5">
<div>
<h5>Filter by standards:</h5>
<div className="d-flex justify-content-between mt-2">
{levels.map((level) => (
<Dropdown_
key={level.id}
id={level.id}
className={"level-" + level.levelNumber}
name = {level.levelNumber}
standards={standards.filter(
(standard) => standard.standardLevel === level.levelNumber
)}
onFilterChange={handelOnFilterChange}
>
{level.levelName}
</Dropdown_>
))}
</div>
</div>
</Container>
);
};
export default Filter;

View File

@ -0,0 +1,84 @@
import React, { useEffect, useState, Fragment } from "react";
import Container from "react-bootstrap/Container";
import Dropdown from "react-bootstrap/Dropdown";
import classes from "../../../Static/styles.module.css";
import ToggleButton from "react-bootstrap/esm/ToggleButton";
import ToggleButtonGroup from "react-bootstrap/esm/ToggleButtonGroup";
import axios from "axios";
const Filter = ({ onFilterChange }) => {
const [levels, setLevels] = useState([]);
const [standards, setStandards] = useState([]);
const [standardsFilter, setStandardsFilter] = useState([]);
// get the filters values to this component
const handelOnFilterChange = (val) => {
// console.log(val);
setStandardsFilter(val);
onFilterChange(val);
};
useEffect(() => {
axios
.get("http://127.0.0.1:8000/levels/")
.then((response) => setLevels(response.data))
.catch((error) => console.log(error));
}, []);
useEffect(() => {
axios
.get("http://127.0.0.1:8000/standards/")
.then((response) => setStandards(response.data))
.catch((error) => console.log(error));
}, []);
return (
<div className="mt-5">
<h5>Filter by standards:</h5>
<div className="d-flex justify-content-between mt-2">
{levels.map((level) => (
<Dropdown key={level.id}>
<Dropdown.Toggle
id={level.id}
className={classes["level-" + level.levelNumber]}
>
{level.levelName}
</Dropdown.Toggle>
<Dropdown.Menu className="w-100">
<ToggleButtonGroup
type="checkbox"
value={standardsFilter}
onChange={handelOnFilterChange}
vertical
name={level.levelNumber}
>
{standards
.filter(
(standard) => standard.standardLevel === level.levelNumber
)
.map((standard, index) => (
<ToggleButton
name="std"
type="checkbox"
variant="outline-secondary"
key={standard.id}
id={`std-btn-${standard.id}`}
//className={classes["comp-btn"]}
value={standard.standardTitle}
>
{standard.standardTitle}
</ToggleButton>
))}
</ToggleButtonGroup>
</Dropdown.Menu>
</Dropdown>
))}
</div>
</div>
);
};
export default Filter;

View File

@ -0,0 +1,9 @@
import React from 'react'
const KeyPhrases=() => {
return (
<h4>KeyPhrases</h4>
)
}
export default KeyPhrases

View File

@ -0,0 +1,84 @@
import React, { useState } from "react";
import Card from "../../UI/Card/Card";
import Container from "react-bootstrap/esm/Container";
import Stack from "react-bootstrap/Stack";
import ResultsItem from "./ResultsItem";
import ResultModal from "../../UI/ResultModal/ResultModal";
import ResultsPagination from "../../UI/ResultsPagination/ResultsPagination";
import PDFGenerator from "../../PDFGenerator/PDFGenerator";
import { PDFDownloadLink } from "@react-pdf/renderer";
import Button from "react-bootstrap/esm/Button";
const Results = (props) => {
const [showModal, setShowModal] = useState(false);
const [selectedResult, setSelectedResult] = useState(null);
const [currentPage, setCurrentPage] = useState(1);
// eslint-disable-next-line
const [postsPerPage, setPostsPerPage] = useState(10);
const lastPostIndex = currentPage * postsPerPage;
const firstPostIndex = lastPostIndex - postsPerPage;
const currentPost = props.results.slice(firstPostIndex, lastPostIndex);
const handleShowModal = (result) => {
setSelectedResult(result);
setShowModal(true);
};
const handleCloseModal = () => {
setShowModal(false);
setSelectedResult(null);
};
return (
<div className="mt-5 mb-5">
{/* <PDFDownloadLink document={<PDFGenerator results={props.results}/>}>
{({loading}) => (loading ? <Button>Loading document...</Button> : <Button>Download</Button>)}
</PDFDownloadLink> */}
{/* <PDFGenerator results={props.results} /> */}
<Card className="secondary p-1">
<h2 className="text-secondary text-center">Searched Phrase</h2>
<Stack gap={3} className="mt-3">
{currentPost.map((result) => (
<ResultsItem
onClick={() => handleShowModal(result)}
key={result.Index}
level={result.Level}
title={result.Title}
heading1={result.Heading1}
paragraph={result.Paragraph}
></ResultsItem>
))}
</Stack>
<ResultsPagination
totalPosts={props.results.length}
postsPerPage={postsPerPage}
setCurrentPage={setCurrentPage}
currentPage={currentPage}
></ResultsPagination>
</Card>
<ResultModal
show={showModal}
handleClose={handleCloseModal}
level={selectedResult ? selectedResult.Level : ""}
module={selectedResult ? selectedResult.Module : ""}
heading1={selectedResult ? selectedResult.Heading1 : ""}
heading2={selectedResult ? selectedResult.Heading2 : ""}
heading3={selectedResult ? selectedResult.Heading3 : ""}
heading4={selectedResult ? selectedResult.Heading4 : ""}
pageNumber={selectedResult ? selectedResult.PageNum : ""}
paragraph={selectedResult ? selectedResult.Paragraph : ""}
></ResultModal>
</div>
);
};
export default Results;

View File

@ -0,0 +1,28 @@
import React from "react";
import Card from "react-bootstrap/Card";
import classes from "../../../Static/styles.module.css"
const ResultsItem = (props) => {
const truncateText = (text, maxLength) =>{
if (text.length > maxLength) {
return text.substring(0, maxLength) + "...";
} else {
return text;
}
}
return (
<Card onClick = {props.onClick}>
<Card.Header className={ classes[`level-text-${props.level}`] }>
Level {props.level}, {props.title}
</Card.Header>
<Card.Body>
<Card.Title>{props.heading1}</Card.Title>
<Card.Text>{truncateText(props.paragraph, 300)} </Card.Text>
</Card.Body>
</Card>
);
};
export default ResultsItem;

View File

@ -0,0 +1,36 @@
import React, { useState } from "react";
import Input from "../../UI/Input/Input";
import Button_ from "../../UI/Button/Button_";
import Form from "react-bootstrap/Form";
import Container from "react-bootstrap/Container";
const Search = (props) => {
return (
<div className="mt-5">
<Form
id="searchForm"
method="get"
className="d-flex align-items-center"
onSubmit={props.onSubmit}
>
<Input
placeholder="Search IDDRS..."
type="text"
id="search_input"
name="phrase"
aria-label="Seach IDDRS..."
aria-describedby="basic-addon1"
onChange={props.onChange}
></Input>
<Button_ id="submitSearch" type="submit" className="btn-default">
Search
</Button_>
</Form>
</div>
);
};
export default Search;

View File

@ -0,0 +1,118 @@
import React, { Fragment } from "react";
import { render } from "react-dom";
import WordCloud from "react-d3-cloud";
import Container from "react-bootstrap/esm/Container";
import Card from "react-bootstrap/Card";
const data = [
{ text: "Disarmament", value: 1000 },
{
text: "Disarmament",
value: 68.0,
},
{
text: "Demobilization",
value: 60.0,
},
{
text: "Reintegration support",
value: 58.0,
},
{
text: "Reinsertion",
value: 57.0,
},
{
text: "Security Sector",
value: 52.0,
},
{
text: "DDR participants",
value: 51.0,
},
{
text: "Integrated Assessments",
value: 48.0,
},
{
text: "Community Violence Reduction",
value: 46.0,
},
{
text: "Transitional Weapons and Ammunition Management",
value: 43.0,
},
{
text: "Children associated with armed forces and groups",
value: 42.0,
},
{
text: "Community based reintegration",
value: 40.0,
},
{
text: "DDR-related tools",
value: 37.0,
},
{
text: "DDR Programme",
value: 31.0,
},
{
text: "DDR Process",
value: 27.0,
},
{
text: "Foreign combatants",
value: 26.0,
},
{
text: "Pre-DDR",
value: 22.0,
},
{
text: "DDR policy",
value: 19.0,
},
{
text: "DDR Strategy",
value: 17.0,
},
{
text: "Eligibility criteria",
value: 13.0,
},
{
text: "Preventing recruitment",
value: 13.0,
},
];
const WordCloud_ = () => {
return (
<div>
<Card>
<h4 className="text-decoration-underline">
Most Frequent Key-Phrases
</h4>
<WordCloud
width={1000}
data={data}
font="Times"
fontStyle="italic"
//fontWeight="bold"
fontSize={(word) => Math.log2(word.value) * 3}
spiral="rectangular"
rotate={0}
fill = "gray"
padding={2}
onWordClick={(event, d) => {
console.log(`onWordClick: ${d.text}`);
}}
/>
</Card>
</div>
);
};
export default WordCloud_;

View File

@ -0,0 +1,69 @@
import React, { Fragment } from "react";
import {
Document,
Page,
Text,
View,
StyleSheet,
Font
} from "@react-pdf/renderer";
// Register font
Font.register({ family: "Times-Roman" });
const styles = StyleSheet.create({
page: {
flexDirection: "row",
backgroundColor: "#E4E4E4",
padding: 10,
},
text: {
fontFamily: "Times-Roman",
fontSize: 12,
},
title: {
fontSize: 14,
}
});
const PDFGenerator = (props) => {
return (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.content}>
{props.results.map((result, index) => (
<Fragment>
<Text key={index} style={[styles.text, styles.title]}>
Level {result.LevelName}
</Text>
<Text key={index} style={[styles.text, styles.title]}>
IDDRS - {result.Module}
</Text>
<Text key={index} style={styles.text}>
{result.Heading1}
</Text>
<Text key={index} style={styles.text}>
{result.Heading2}
</Text>
<Text key={index} style={styles.text}>
{result.Heading3}
</Text>
<Text key={index} style={styles.text}>
{result.Heading4}
</Text>
<Text key={index} style={styles.text}>
{result.Paragraph}
</Text>
<Text key={index} style={styles.text}>
{result.PageNum}
</Text>
</Fragment>
))}
</View>
</Page>
</Document>
);
};
export default PDFGenerator;

View File

@ -0,0 +1,12 @@
import React from "react";
import Button from "react-bootstrap/Button";
const Button_ = (props) => {
return (
<Button id={props.id} type={props.type} className={props.class}>
{props.children}
</Button>
);
};
export default Button_;

View File

@ -0,0 +1,10 @@
import React from "react";
import classes from './Card.module.css'
const Card = props => {
return (
<div className={`${classes.card} ${props.className} `}>{props.children}</div>
);
}
export default Card;

View File

@ -0,0 +1,5 @@
.card{
/* background-color: antiquewhite; */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
border-radius: 10px;
}

View File

@ -0,0 +1,14 @@
import React from "react";
import Dropdown from "react-bootstrap/Dropdown";
import Form from "react-bootstrap/Form";
const DropdownItem = (props) => {
return (
<Form.Check type="checkbox" id={`check-api-${props.id}`} label={props.children} isValid>
</Form.Check>
);
};
export default DropdownItem;

View File

@ -0,0 +1,56 @@
import React, { useState, useEffect } from "react";
import Dropdown from "react-bootstrap/Dropdown";
import DropdownItem from "./DropdownItem";
import classes from "../../../Static/styles.module.css";
import ToggleButton from "react-bootstrap/esm/ToggleButton";
import ToggleButtonGroup from "react-bootstrap/esm/ToggleButtonGroup";
const Dropdown_ = (props) => {
const [filterValues, setFilterValues] = useState({});
// Handle change event for ToggleButtonGroup
const handleToggleChange = (name, values) => {
setFilterValues((prevState) => ({
...prevState,
[name]: values,
}));
props.onFilterChange(filterValues)
//console.log(filterValues);
};
return (
<Dropdown>
<Dropdown.Toggle id={props.id} className={classes[props.className]}>
{props.children}
</Dropdown.Toggle>
<Dropdown.Menu className="w-100">
<ToggleButtonGroup
type="checkbox"
value={filterValues[props.name] || []}
onChange={(values) => handleToggleChange(props.name, values)}
vertical
name={props.name}
>
{props.standards.map((standard, index) => (
<ToggleButton
name="std"
type="checkbox"
variant="outline-secondary"
key={standard.id}
id={`std-btn-${standard.id}`}
//className={classes["comp-btn"]}
value={standard.standardTitle}
>
{standard.standardTitle}
</ToggleButton>
))}
</ToggleButtonGroup>
</Dropdown.Menu>
</Dropdown>
);
};
export default Dropdown_;

View File

@ -0,0 +1,22 @@
import React from "react";
import Form from "react-bootstrap/Form";
import InputGroup from "react-bootstrap/InputGroup";
//import classes from "./input.module.css"
const Input = (props) => {
return (
<Form.Control
placeholder={props.placeholder}
type={props.type}
id={props.id}
name={props.name}
aria-label={props['aria-label']}
aria-describedby = {props['aria-describedby']}
onChange = {props.onChange}
/>
);
};
export default Input;

View File

View File

@ -0,0 +1,38 @@
import React, { useState } from "react";
import Modal from "react-bootstrap/Modal";
import Button from "react-bootstrap/esm/Button";
import classes from "../../../Static/styles.module.css"
const ResultModal = (props) => {
return (
<Modal
{...props}
size='xl'
aria-labelledby="example-custom-modal-styling-title"
centered
onHide={props.handleClose}
>
<Modal.Header closeButton>
<Modal.Title id="example-custom-modal-styling-title">
<div className={classes[`level-text-${props.level}`]}>Level {props.level}</div>
<div className="mb-3">IDDRS - {props.module}</div>
<p className="fs-5 fw-light mb-0">{props.heading1}</p>
<p className="fs-6 fw-light mb-0">{props.heading2}</p>
<p className="fs-6 fw-light mb-0">{props.heading3}</p>
<p className="fs-6 fw-light mb-0">{props.heading4}</p>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p className="fs-6 fw-light">{props.paragraph}</p>
<div className="fs-5 fw-light mt-4"><p class="text-end">Page: {props.pageNumber}</p></div>
</Modal.Body>
<Modal.Footer>
<Button onClick={props.handleClose}>Close</Button>
</Modal.Footer>
</Modal>
);
};
export default ResultModal;

View File

@ -0,0 +1,103 @@
import React, { useState } from "react";
import classes from "./ResultsPagination.module.css";
import Button from "react-bootstrap/esm/Button";
import Pagination from "react-bootstrap/Pagination";
const ResultsPagination = ({
totalPosts,
postsPerPage,
setCurrentPage,
currentPage,
}) => {
const [pageNumberLimit, setpageNumberLimit] = useState(5);
const [maxPageNumberLimit, setmaxPageNumberLimit] = useState(5);
const [minPageNumberLimit, setminPageNumberLimit] = useState(0);
//console.log(maxPageNumberLimit, minPageNumberLimit);
let pages = [];
for (let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) {
pages.push(i);
}
const handleNextbtn = () => {
setCurrentPage(currentPage + 1);
if (currentPage + 1 > maxPageNumberLimit) {
setmaxPageNumberLimit(maxPageNumberLimit + pageNumberLimit);
setminPageNumberLimit(minPageNumberLimit + pageNumberLimit);
}
};
const handlePrevbtn = () => {
setCurrentPage(currentPage - 1);
if ((currentPage - 1) % pageNumberLimit == 0) {
setmaxPageNumberLimit(maxPageNumberLimit - pageNumberLimit);
setminPageNumberLimit(minPageNumberLimit - pageNumberLimit);
}
};
const handleFirstbtn = () => {
setCurrentPage(1);
setmaxPageNumberLimit(5);
setminPageNumberLimit(0);
};
const handleLastbtn = () => {
setCurrentPage(pages.slice(-1));
setmaxPageNumberLimit(Math.floor(pages.slice(-1) / 5) * 5);
setminPageNumberLimit(Math.floor(pages.slice(-1) / 5) * 5 - 5);
console.log(currentPage)
};
let pageIncrementBtn = null;
if (pages.length > maxPageNumberLimit) {
pageIncrementBtn = <p> &hellip; </p>;
}
let pageDecrementBtn = null;
if (minPageNumberLimit >= 1) {
pageDecrementBtn = <p> &hellip; </p>;
}
return (
<div className={classes.pagination}>
<Button onClick={handleFirstbtn} variant="primary">
{"<<"}
</Button>
<Button
onClick={handlePrevbtn}
disabled={currentPage == pages[0] ? true : false}
variant="secondary"
>
Prev
</Button>
{pageDecrementBtn}
{pages.map((page, index) => {
if (page < maxPageNumberLimit + 1 && page > minPageNumberLimit) {
return (
<Button
key={index}
onClick={() => setCurrentPage(page)}
className={page == currentPage ? classes.active : ""}
>
{page}
</Button>
);
}
})}
{pageIncrementBtn}
<Button
onClick={handleNextbtn}
disabled={currentPage == pages[pages.length - 1] ? true : false}
variant="secondary"
>
Next
</Button>
<Button onClick={handleLastbtn} variant="primary">
{">>"}
</Button>
</div>
);
};
export default ResultsPagination;

View File

@ -0,0 +1,27 @@
.pagination {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 1rem;
margin-bottom: 1rem;
}
.pagination button {
font-family: inherit;
font-weight: 600;
font-size: 16px;
margin: 0 10px;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
background: transparent;
color: #000000;
border-color: #000000;
}
.pagination button.active {
font-weight: 900;
border-color: #101010;
background: #0275d8;
color: #101010;
}

7
src/Static/functions.js Normal file
View File

@ -0,0 +1,7 @@
function truncateText(text, maxLength) {
if (text.length > maxLength) {
return text.substring(0, maxLength) + "...";
} else {
return text;
}
}

View File

@ -0,0 +1,53 @@
.level-1 {
background-color: #F07F4E !important;
border: 0px !important;
}
.level-2 {
background-color: #008DCA !important;
border: 0px !important;
}
.level-3 {
background-color: #00A554 !important;
border: 0px !important;
}
.level-4 {
background-color: #7366A3 !important;
border: 0px !important;
}
.level-5 {
background-color: #D10007 !important;
border: 0px !important;
}
.level-6 {
background-color: #CF7AB2 !important;
border: 0px !important;
}
.level-text-1 {
color: #F07F4E !important;
}
.level-text-2 {
color: #008DCA !important;
}
.level-text-3 {
color: #00A554 !important;
}
.level-text-4 {
color: #7366A3 !important;
}
.level-text-5 {
color: #D10007 !important;
}
.level-text-6 {
color: #CF7AB2 !important;
}

View File

@ -1,9 +1,10 @@
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root')); const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( root.render(
<React.StrictMode> <React.StrictMode>