From bd98124b6f88eaee96d5f1576eafdcca0547d783 Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Sun, 15 Oct 2023 17:38:25 +0300 Subject: [PATCH 01/18] first connection --- FrontEnd/src/App.js | 2 + .../HeaderFooter/header/navbar/SearchBox.jsx | 44 +++-- .../header/navbar/SearchBox.module.css | 58 ++++++- FrontEnd/src/components/SearchPage/Search.js | 142 ++++++++++++++++ .../src/components/SearchPage/img/frame42.png | Bin 0 -> 462 bytes .../SearchPage/img/link_to_left.svg | 3 + .../SearchPage/img/link_to_right.svg | 3 + FrontEnd/src/components/SearchPage/index.js | 17 ++ .../SearchPage/search_field/SearchResults.js | 33 ++++ .../SearchPage/search_field/Text.css | 51 ++++++ .../search_field/companies/Companies.js | 106 ++++++++++++ .../search_field/companies/CompaniesCards.css | 160 ++++++++++++++++++ .../companies/img/wish_list_checklist.svg | 3 + .../img/wish_list_checklist_added.svg | 3 + .../search_field/companies/variables.css | 12 ++ .../src/components/SearchPage/search_page.css | 117 +++++++++++++ 16 files changed, 743 insertions(+), 11 deletions(-) create mode 100644 FrontEnd/src/components/SearchPage/Search.js create mode 100644 FrontEnd/src/components/SearchPage/img/frame42.png create mode 100644 FrontEnd/src/components/SearchPage/img/link_to_left.svg create mode 100644 FrontEnd/src/components/SearchPage/img/link_to_right.svg create mode 100644 FrontEnd/src/components/SearchPage/index.js create mode 100644 FrontEnd/src/components/SearchPage/search_field/SearchResults.js create mode 100644 FrontEnd/src/components/SearchPage/search_field/Text.css create mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/Companies.js create mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.css create mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist.svg create mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist_added.svg create mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/variables.css create mode 100644 FrontEnd/src/components/SearchPage/search_page.css diff --git a/FrontEnd/src/App.js b/FrontEnd/src/App.js index b950ab66..cbb52013 100644 --- a/FrontEnd/src/App.js +++ b/FrontEnd/src/App.js @@ -5,6 +5,7 @@ import AdminPage from './components/adminPage/AdminPage'; import BasicPage from './components/basicPage/BasicPage'; import { AuthContext } from './context'; import { useProvideAuth } from './hooks'; +import { Search } from './components/SearchPage/Search'; function App() { const auth = useProvideAuth(); @@ -16,6 +17,7 @@ function App() { } /> } /> + } /> diff --git a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx index d439f56b..d9a1aa5c 100644 --- a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx +++ b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx @@ -1,15 +1,39 @@ -import css from './SearchBox.module.css'; +import { useState } from 'react'; import icon_search from './search-icon.svg'; +import { useNavigate } from 'react-router-dom'; +import css from './SearchBox.module.css'; + +function SearchBox() { + const navigate = useNavigate(); + + const [searchTerm, setSearchTerm] = useState(''); + const searchPage = 'search'; -function SearchBox () { - return ( -
-
- -
- -
- ); + const handleSearch = (searchTerm, searchPage) => { + if (searchTerm.trim() !== '') { + navigate(`/${searchPage}/?search_field=${searchTerm}`); + } + }; + return ( +
+
+ setSearchTerm(e.target.value)} + /> +
+ +
+ ); } export default SearchBox; diff --git a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css index e3e4f4c7..990641f2 100644 --- a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css +++ b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css @@ -1,4 +1,4 @@ -.header-search-box { +/* .header-search-box { display: flex; align-items: center; flex-shrink: 0; @@ -53,4 +53,60 @@ textarea:focus, .header-search-form__input:focus{ border: none; outline: none; +} */ + +.header-search-box { + display: flex; + align-items: center; + flex-shrink: 0; + width: 264px; + + border-radius: 2px; + border: 1px solid #d9d9d9; + background: #fff; +} + +.header-search-form { + display: flex; + padding: 4px 12px; + align-items: flex-start; + gap: 10px; + flex: 1 0 0; +} + +.header-search-form__input { + display: flex; + padding: 1px 0px; + align-items: flex-start; + gap: 10px; + flex: 1 0 0; + border: none; +} + +.header-search-form__addon { + background-color: transparent; + cursor: pointer; + border: 1px solid rgba(0, 0, 0, 0.25); +} + +.header-search-form__addon img { + width: 20px; + height: 20px; +} + +.header-search-form__input::placeholder { + color: rgba(0, 0, 0, 0.25); + font-feature-settings: 'calt' off; + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; + letter-spacing: -0.14px; +} + +textarea:focus, +.header-search-form__input:focus { + border: none; + outline: none; } diff --git a/FrontEnd/src/components/SearchPage/Search.js b/FrontEnd/src/components/SearchPage/Search.js new file mode 100644 index 00000000..e9fe2b2f --- /dev/null +++ b/FrontEnd/src/components/SearchPage/Search.js @@ -0,0 +1,142 @@ +import axios from 'axios'; +import { useState, useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; +import BreadCrumbs from '../BreadCrumbs/BreadCrumbs'; +import SearchResults from './search_field/SearchResults'; +import frame42 from './img/frame42.png'; +import link_to_left from './img/link_to_left.svg'; +import link_to_right from './img/link_to_right.svg'; +import './search_page.css'; + +const ITEMS_PER_PAGE = 6; + +export function Search(props) { + const [searchResults, setSearchResults] = useState([]); + const [searchPerformed, setSearchPerformed] = useState(false); + const [error, setError] = useState(null); + + const location = useLocation(); + const searchParams = new URLSearchParams(location.search); + const searchTerm = searchParams.get('search_field'); + const servedAddress = process.env.REACT_APP_BASE_API_URL; + const searchUrl = 'search'; + + useEffect(() => { + if (searchTerm) { + // Make an AJAX request to Django API to get search results + axios + .get(`${servedAddress}/api/${searchUrl}/?name=${searchTerm}`) + .then((response) => { + setSearchResults(response.data); + setSearchPerformed(true); + setError(null); // Clear error on successful response + }) + .catch((error) => { + console.error('Error fetching search results:', error); + setError(error.response ? error.response.data : 'An error occurred'); + }); + } + }, [searchTerm, servedAddress, searchUrl]); + + const [currentPage, setCurrentPage] = useState(1); + const totalItems = searchResults.length; + const totalPages = Math.ceil(totalItems / ITEMS_PER_PAGE); + + const startIndex = (currentPage - 1) * ITEMS_PER_PAGE; + const endIndex = startIndex + ITEMS_PER_PAGE; + const displayedResults = searchResults.slice(startIndex, endIndex); + + const handlePageChange = (newPage) => { + setCurrentPage(newPage); + }; + + return ( +
+ +
+ frame +
+ {searchResults && ( +

+ РЕЗУЛЬТАТІВ ЗА ПОШУКОМ{' '} + {searchTerm} :{' '} + {searchResults.length > 0 ? searchResults.length : 0} +

+ )} +
+
+
+ {!error && searchResults.length > 0 ? ( + <> + +
+ + ) : ( +

+ Пошук не дав результатів: компанії з іменем{' '} + + {searchTerm} + {' '} + не було виявлено на даний момент +

+ )} +
+
+ {totalPages > 1 && ( +
+ {currentPage > 1 && ( + + )} + {currentPage > 1 && ( + <> + + {currentPage > 2 && ...} + + )} + {Array.from({ length: totalPages }, (_, i) => { + if ( + i === 2 || + i === totalPages || + (i >= currentPage - 1 && i <= currentPage) + ) { + return ( + + ); + } + return null; + })} + {currentPage < totalPages - 1 && ( + <> + {currentPage < totalPages - 1 && ( + ... + )} + + + )} + {currentPage < totalPages && ( + + )} +
+ )} +
+
+
+ ); +} diff --git a/FrontEnd/src/components/SearchPage/img/frame42.png b/FrontEnd/src/components/SearchPage/img/frame42.png new file mode 100644 index 0000000000000000000000000000000000000000..e197f19d47a2276f9d32582ba15a606b01364b27 GIT binary patch literal 462 zcmeAS@N?(olHy`uVBq!ia0vp^n}K*52OE%_TDr3gNO2Z;L>4nJa0`PlBg3pY55jgR3=A9lx&I`x0_BoDT^vIy7~kG8%w={IalL3S&1}fxY{2U5 zA<5P#z^2KpC?eLRDA5rls*; bl9&H5x5vblPk))A3UaZhtDnm{r-UW|5WSnV literal 0 HcmV?d00001 diff --git a/FrontEnd/src/components/SearchPage/img/link_to_left.svg b/FrontEnd/src/components/SearchPage/img/link_to_left.svg new file mode 100644 index 00000000..84937931 --- /dev/null +++ b/FrontEnd/src/components/SearchPage/img/link_to_left.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/FrontEnd/src/components/SearchPage/img/link_to_right.svg b/FrontEnd/src/components/SearchPage/img/link_to_right.svg new file mode 100644 index 00000000..450b2ecd --- /dev/null +++ b/FrontEnd/src/components/SearchPage/img/link_to_right.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/FrontEnd/src/components/SearchPage/index.js b/FrontEnd/src/components/SearchPage/index.js new file mode 100644 index 00000000..d563c0fb --- /dev/null +++ b/FrontEnd/src/components/SearchPage/index.js @@ -0,0 +1,17 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; +import App from './App'; +import reportWebVitals from './reportWebVitals'; + +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render( + + + +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js new file mode 100644 index 00000000..8dc01cba --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js @@ -0,0 +1,33 @@ +import MainCompanies from './companies/Companies'; +import './Text.css'; + +const SearchResults = ({ results, displayedResults, isAuthorized }) => { + let error = null; + + if (results && results.error) { + error = results.error; + } + + return ( +
+ {!error && ( + <> +
+
+ {displayedResults.map((result, resultIndex) => ( +
+ +
+ ))} +
+
+ + )} +
+ ); +}; + +export default SearchResults; diff --git a/FrontEnd/src/components/SearchPage/search_field/Text.css b/FrontEnd/src/components/SearchPage/search_field/Text.css new file mode 100644 index 00000000..aad8d700 --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/Text.css @@ -0,0 +1,51 @@ +@import './companies/variables.css'; + +.new-companies-main { + width: 1304px; + display: flex; + padding: 80px 104px; + flex-direction: column; + align-items: flex-start; + gap: 24px; + background: var(--main_light-color); +} +.new-companies { + display: flex; + align-items: center; + gap: 800px; +} +.new-companies-main__header { + width: 444px; + color: var(--text-color); + text-transform: uppercase; + font-family: Inter; + font-size: 20px; + font-style: normal; + font-weight: 700; + line-height: 120%; +} +.new-companies-block { + display: flex; + width: 1304px; + padding: 16px 8px; + flex-direction: column; + align-items: left; + gap: 36px; +} +.new-companies-block__row { + display: flex; + align-items: flex-start; + gap: 60px; +} + +.row { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: -10px; /* spacess beetwen ecompanies */ +} + +.col-md-4 { + flex-basis: calc(33, 3% - 80px); /* 3 companies per row */ + margin: 10px; /* spacess beetwen ecompanies */ +} diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js new file mode 100644 index 00000000..8b90632b --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js @@ -0,0 +1,106 @@ +import { Link } from 'react-router-dom'; +import wish_list_checklist from './img/wish_list_checklist.svg'; +import wish_list_checklist_added from './img/wish_list_checklist_added.svg'; +import './CompaniesCards.css'; + +const MainCompanies = ({ companyData, isAuthorized }) => { + const currentDate = new Date(); + const currentYear = currentDate.getFullYear(); + + // those variables we would use for axios to get data from beckend + // get saved list code here + const usersSavedList = []; + + // add company to saved list code here + // const addToSavedList = (profile_id) => {}; + + // del company from saved list code here + // const delFromSavedList = (profile_id) => {}; + + return ( +
+
+
+ {companyData.comp_name} +
+
+
+
+ {companyData.comp_category + .map((category) => category.name) + .join(' ')} +
+
+ + {companyData.comp_name} + +
+
+
+
+ {companyData.comp_address} +
+
+
+
+
+ {currentYear - companyData.comp_year_of_foundation} років + досвіду +
+
+
+ + {/* if user is authorized - show add to favorite button*/} + {isAuthorized === true && ( + <> + {/* Add checking if company is in user list */} + {usersSavedList.includes(companyData.profile_id) ? ( + <> +
+ {/* if company added - del from saved list */} + +
+ + ) : ( + <> +
+ {/* if compony not added - add to saved list */} + +
+ + )} + + )} +
+
+
+
+
+ {`${companyData.comp_name} +
+
+
+ ); +}; + +export default MainCompanies; diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.css b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.css new file mode 100644 index 00000000..67c637ee --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.css @@ -0,0 +1,160 @@ +@import 'variables.css'; + +.product-card { + width: 360px; + display: block; + align-items: center; + box-shadow: 0 4px 8px 0 var(--companies-card-box-shadow); + border-radius: 11px; + transition: transform 0.2s ease; + position: relative; +} +.product-card:hover { + transform: scale(1.1); +} +.product-card__block { + display: flex; + flex-direction: column; + align-items: flex-start; +} +.product-card__image-frame { + width: 360px; + height: 220px; +} +.product-card__image { + width: 360px; + height: 290px; + flex-shrink: 0; + border-radius: 11px; + object-fit: cover; +} +.product-card__text-block { + display: flex; + padding: 20px 16.02px; + flex-direction: column; + align-items: flex-start; + gap: 16px; + border-radius: 0 0 12px 12px; + background: var(--main_light-color); +} +.product-card__text-block__header { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 12px; +} +.product-card__category-text { + color: var(--companies-card-lover-text); + text-align: center; + font-family: Inter, sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 700; + line-height: 120%; /* 19.2px */ +} +.product-card__name-text { + width: 328px; + height: 48px; + color: var(--text-color); + font-family: Inter, sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 700; + line-height: 120%; /* 24px */ + text-transform: uppercase; +} + +.product-card__name-text_link { + text-decoration: none; /* delete underline */ + color: var(--text-color); +} + +.product-card__name-text_link:visited { + color: var(--text-color); +} + +.product-card__address-text { + width: 328px; + color: var(--companies-card-address); + font-feature-settings: 'calt' off; + font-family: Inter, sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.14px; +} +.product-card__badges-block { + width: 100%; + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 8px; +} +.product-card__badges { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background: var(--main_light-color); +} +.product-card__badge { + display: flex; + padding: 2px 8px; + justify-content: center; + align-items: center; + border-radius: 100px; + background: var(--pagination-style-color); +} +.product-card__badge-text { + color: var(--main_light-color); + text-align: center; + font-feature-settings: 'calt' off; + font-family: Inter, sans-serif; + font-size: 10px; + font-style: normal; + font-weight: 600; + line-height: 16px; /* 160% */ + text-transform: uppercase; +} +.product-card__logo { + width: 64px; + height: 64px; + position: absolute; + right: 16px; + bottom: 159.5px; +} +.product-card__logo-ellipse { + width: 64px; + height: 64px; + flex-shrink: 0; + background: var(--main_light-color); + left: 0; + top: 0; + border-radius: 9999px; + box-shadow: 0 0 2px rgba(65, 64, 69, 0.2); +} +.product-card__logo-image { + width: 54px; + height: 54px; + flex-shrink: 0; + border-radius: 26px; + background: var(--main_light-color); + left: 5px; + top: 5px; + position: absolute; +} + +.align_items_left { + text-align: left; +} + +.product-card__buttons { + color: var(--companies-card-button); + border: none; + background-color: var(--main_light-color); +} + +.product-card__buttons:hover { + cursor: pointer; +} diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist.svg b/FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist.svg new file mode 100644 index 00000000..15a3a9bd --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist.svg @@ -0,0 +1,3 @@ + + + diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist_added.svg b/FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist_added.svg new file mode 100644 index 00000000..6a988c08 --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/companies/img/wish_list_checklist_added.svg @@ -0,0 +1,3 @@ + + + diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/variables.css b/FrontEnd/src/components/SearchPage/search_field/companies/variables.css new file mode 100644 index 00000000..5ea0350b --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/companies/variables.css @@ -0,0 +1,12 @@ +:root { + --text-color: #292e32; + --main-style-signs-color: #0b6c61; + --main_light-color: white; + --pagination-style-color: #1f9a7c; + --link-color: #61dafb; + --companies-card-box-shadow: rgba(65, 64, 69, 0.2); + --companies-card-lover-text: #767f86; + --companies-card-address: #59636a; + --companies-card-button: green; + --new-companies-main: #f1fff7; +} diff --git a/FrontEnd/src/components/SearchPage/search_page.css b/FrontEnd/src/components/SearchPage/search_page.css new file mode 100644 index 00000000..1b4c4539 --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_page.css @@ -0,0 +1,117 @@ +@import './search_field/companies/variables.css'; + +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.main_block_outer { + padding-top: 10px; +} + +.new-companies-main { + background-color: var(--new-companies-main); +} + +.App-header { + background-color: var(--text-color); + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: var(--white-color); +} + +.App-link { + color: var(--link-color); +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.main_block { + position: relative; +} + +.new-companies-search_count { + display: flex; + margin: auto; + padding-left: 7%; +} + +.search_field_entered_value { + color: var(----main-style-signs-color); + font: Inter; + font-weight: 600; + font-style: italic; +} + +.search_results_text { + font: Inter; + font-weight: 700; +} + +.search_result_error { + font-weight: 600; + color: var(--text-color); + font: Inter; +} + +.search_result_error_search_value { + color: var(--main-style-signs-color); +} + +.frame-img-right { + position: absolute; + top: 30px; + right: 0; + transform: translateY(-50%); +} + +.new-companies-result_pages { + padding: 40px; +} + +.pagination { + background-color: var(--main_light-color); + display: flex; + justify-content: center; + align-items: center; + margin-top: 20px; +} + +.pagination button { + all: unset; + border: none; + font-size: 16px; + font-weight: 500; + padding: 8px 16px; + margin: 0 4px; + cursor: pointer; +} + +.pagination button.active { + background-color: none; + color: var(--pagination-style-color); + border: 1px solid var(--pagination-style-color); + border-radius: 5px; + transition: background-color 0.3s, color 0.3s; +} From b48a398a8e918e5c338d77c453cc33e508e52a51 Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Mon, 16 Oct 2023 14:43:27 +0300 Subject: [PATCH 02/18] work but uncomely --- .../HeaderFooter/header/navbar/Menu.jsx | 35 +++++++++---------- .../HeaderFooter/header/navbar/SearchBox.jsx | 2 +- FrontEnd/src/components/SearchPage/Search.js | 4 +-- .../search_field/companies/Companies.js | 7 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/FrontEnd/src/components/HeaderFooter/header/navbar/Menu.jsx b/FrontEnd/src/components/HeaderFooter/header/navbar/Menu.jsx index 88e52c4f..4e05cb98 100644 --- a/FrontEnd/src/components/HeaderFooter/header/navbar/Menu.jsx +++ b/FrontEnd/src/components/HeaderFooter/header/navbar/Menu.jsx @@ -3,27 +3,26 @@ import css from './Menu.module.css'; import { HashLink } from 'react-router-hash-link'; const MENU_LINKS = [ - { - id: 'm0', - title: 'Головна', - link: '/' - }, - { - title: 'Компанії', - link: '/profiles/companies' - }, - { - title: 'Стартапи', - link: '/profiles/startups' - }, - { - title: 'Про нас', - link: '/#about-us' - }, + { + id: 'm0', + title: 'Головна', + link: '/', + }, + { + title: 'Компанії', + link: '/profiles/companies', + }, + { + title: 'Стартапи', + link: '/profiles/startups', + }, + { + title: 'Про нас', + link: '/#about-us', + }, ]; function Menu() { - console.log(MENU_LINKS.map((element) => (element.title.startsWith('/#')))); return (
{MENU_LINKS.map((element) => ( diff --git a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx index d9a1aa5c..afb10fd5 100644 --- a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx +++ b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx @@ -11,7 +11,7 @@ function SearchBox() { const handleSearch = (searchTerm, searchPage) => { if (searchTerm.trim() !== '') { - navigate(`/${searchPage}/?search_field=${searchTerm}`); + navigate(`/${searchPage}/?name=${searchTerm}`); } }; return ( diff --git a/FrontEnd/src/components/SearchPage/Search.js b/FrontEnd/src/components/SearchPage/Search.js index e9fe2b2f..df823892 100644 --- a/FrontEnd/src/components/SearchPage/Search.js +++ b/FrontEnd/src/components/SearchPage/Search.js @@ -17,7 +17,7 @@ export function Search(props) { const location = useLocation(); const searchParams = new URLSearchParams(location.search); - const searchTerm = searchParams.get('search_field'); + const searchTerm = searchParams.get('name'); const servedAddress = process.env.REACT_APP_BASE_API_URL; const searchUrl = 'search'; @@ -25,7 +25,7 @@ export function Search(props) { if (searchTerm) { // Make an AJAX request to Django API to get search results axios - .get(`${servedAddress}/api/${searchUrl}/?name=${searchTerm}`) + .get(`${servedAddress}/api/search/?name=${searchTerm}`) .then((response) => { setSearchResults(response.data); setSearchPerformed(true); diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js index 8b90632b..8214acaf 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js +++ b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js @@ -30,9 +30,10 @@ const MainCompanies = ({ companyData, isAuthorized }) => {
- {companyData.comp_category - .map((category) => category.name) - .join(' ')} + {companyData.comp_category && + companyData.comp_category + .map((category) => category.name) + .join(' ')}
Date: Mon, 16 Oct 2023 15:18:41 +0300 Subject: [PATCH 03/18] fix categories --- .../search_field/companies/Companies.js | 21 +++++++++---------- search/serializers.py | 3 +++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js index 8214acaf..b2a20acb 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js +++ b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js @@ -23,37 +23,36 @@ const MainCompanies = ({ companyData, isAuthorized }) => {
{companyData.comp_name}
- {companyData.comp_category && - companyData.comp_category + {companyData.categories && + companyData.categories .map((category) => category.name) .join(' ')}
- {companyData.comp_name} + {companyData.name}
- {companyData.comp_address} + {companyData.address}
- {currentYear - companyData.comp_year_of_foundation} років - досвіду + {currentYear - companyData.founded} років досвіду
@@ -62,7 +61,7 @@ const MainCompanies = ({ companyData, isAuthorized }) => { {isAuthorized === true && ( <> {/* Add checking if company is in user list */} - {usersSavedList.includes(companyData.profile_id) ? ( + {usersSavedList.includes(companyData.id) ? ( <>
{/* if company added - del from saved list */} @@ -96,7 +95,7 @@ const MainCompanies = ({ companyData, isAuthorized }) => {
{`${companyData.comp_name}
diff --git a/search/serializers.py b/search/serializers.py index 324eddcf..42e364e3 100644 --- a/search/serializers.py +++ b/search/serializers.py @@ -1,9 +1,12 @@ from rest_framework import serializers from profiles.models import Profile, Category +from profiles.serializers import CategorySerializer class CompanySerializers(serializers.ModelSerializer): + # activities = ActivitySerializer(many=True, read_only=True) + categories = CategorySerializer(many=True, read_only=True) class Meta: model = Profile fields = ( From 8d3cfc3900daa7b59dd0b29090d73be3c83bccee Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Mon, 16 Oct 2023 15:21:20 +0300 Subject: [PATCH 04/18] delete comment --- search/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search/serializers.py b/search/serializers.py index 42e364e3..86a19c80 100644 --- a/search/serializers.py +++ b/search/serializers.py @@ -5,8 +5,8 @@ class CompanySerializers(serializers.ModelSerializer): - # activities = ActivitySerializer(many=True, read_only=True) categories = CategorySerializer(many=True, read_only=True) + class Meta: model = Profile fields = ( From d65e2a7a0081087f29a1210059d0fd26a941b678 Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Tue, 17 Oct 2023 14:11:22 +0300 Subject: [PATCH 05/18] fix comments, delete index.js --- .../header/navbar/SearchBox.module.css | 57 ------------------- FrontEnd/src/components/SearchPage/index.js | 17 ------ .../SearchPage/search_field/SearchResults.js | 24 ++++---- .../search_field/companies/Companies.js | 8 --- 4 files changed, 11 insertions(+), 95 deletions(-) delete mode 100644 FrontEnd/src/components/SearchPage/index.js diff --git a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css index 990641f2..e289630f 100644 --- a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css +++ b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.module.css @@ -1,60 +1,3 @@ -/* .header-search-box { - display: flex; - align-items: center; - flex-shrink: 0; - width: 264px; - - border-radius: 2px; - border: 1px solid #D9D9D9; - background: #FFF; -} - -.header-search-form { - display: flex; - padding: 4px 12px; - align-items: flex-start; - gap: 10px; - flex: 1 0 0; -} - -.header-search-form__input { - display: flex; - padding: 1px 0px; - align-items: flex-start; - gap: 10px; - flex: 1 0 0; - border: none; -} - -.header-search-form__addon { - display: flex; - padding: 9px; - width: 14px; - height: 14px; - justify-content: center; - align-items: center; - gap: 8px; - align-self: stretch; - border-left: 1px solid #D9D9D9;; -} - -.header-search-form__input::placeholder { - color: rgba(0, 0, 0, 0.25); - font-feature-settings: 'calt' off; - - font-family: Inter; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 20px; - letter-spacing: -0.14px; -} - -textarea:focus, .header-search-form__input:focus{ - border: none; - outline: none; -} */ - .header-search-box { display: flex; align-items: center; diff --git a/FrontEnd/src/components/SearchPage/index.js b/FrontEnd/src/components/SearchPage/index.js deleted file mode 100644 index d563c0fb..00000000 --- a/FrontEnd/src/components/SearchPage/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js index 8dc01cba..3623fd43 100644 --- a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js +++ b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js @@ -11,20 +11,18 @@ const SearchResults = ({ results, displayedResults, isAuthorized }) => { return (
{!error && ( - <> -
-
- {displayedResults.map((result, resultIndex) => ( -
- -
- ))} -
+
+
+ {displayedResults.map((result, resultIndex) => ( +
+ +
+ ))}
- +
)}
); diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js index b2a20acb..0ec3448c 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js +++ b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js @@ -7,16 +7,8 @@ const MainCompanies = ({ companyData, isAuthorized }) => { const currentDate = new Date(); const currentYear = currentDate.getFullYear(); - // those variables we would use for axios to get data from beckend - // get saved list code here const usersSavedList = []; - // add company to saved list code here - // const addToSavedList = (profile_id) => {}; - - // del company from saved list code here - // const delFromSavedList = (profile_id) => {}; - return (
From a15ef4813b06dda184e65e5feeb63bfd2c11baea Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Tue, 17 Oct 2023 15:21:53 +0300 Subject: [PATCH 06/18] module.css --- .../components/HeaderFooter/header/Header.jsx | 24 +++++----- FrontEnd/src/components/SearchPage/Search.js | 2 +- .../SearchPage/search_field/SearchResults.js | 8 ++-- .../{Text.css => Text.module.css} | 0 .../search_field/companies/Companies.js | 44 ++++++++++--------- ...iesCards.css => CompaniesCards.module.css} | 0 ...search_page.css => search_page.module.css} | 0 7 files changed, 42 insertions(+), 36 deletions(-) rename FrontEnd/src/components/SearchPage/search_field/{Text.css => Text.module.css} (100%) rename FrontEnd/src/components/SearchPage/search_field/companies/{CompaniesCards.css => CompaniesCards.module.css} (100%) rename FrontEnd/src/components/SearchPage/{search_page.css => search_page.module.css} (100%) diff --git a/FrontEnd/src/components/HeaderFooter/header/Header.jsx b/FrontEnd/src/components/HeaderFooter/header/Header.jsx index 2d936807..c8c62dd6 100644 --- a/FrontEnd/src/components/HeaderFooter/header/Header.jsx +++ b/FrontEnd/src/components/HeaderFooter/header/Header.jsx @@ -2,17 +2,19 @@ import css from './Header.module.css'; import HeaderMenu from './menu/HeaderMenu'; import Navbar from './navbar/Navbar'; -function Header (props) { - return ( -
-
- -
- {props.page === 'login' || props.page === 'registration' ? (null): ()} -
-
-
- ); +function Header(props) { + return ( +
+
+ +
+ {props.page === 'login' || props.page === 'registration' ? null : ( + + )} +
+
+
+ ); } export default Header; diff --git a/FrontEnd/src/components/SearchPage/Search.js b/FrontEnd/src/components/SearchPage/Search.js index df823892..c6c00ce3 100644 --- a/FrontEnd/src/components/SearchPage/Search.js +++ b/FrontEnd/src/components/SearchPage/Search.js @@ -6,7 +6,7 @@ import SearchResults from './search_field/SearchResults'; import frame42 from './img/frame42.png'; import link_to_left from './img/link_to_left.svg'; import link_to_right from './img/link_to_right.svg'; -import './search_page.css'; +import './search_page.module.css'; const ITEMS_PER_PAGE = 6; diff --git a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js index 3623fd43..a812d07e 100644 --- a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js +++ b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js @@ -1,5 +1,5 @@ import MainCompanies from './companies/Companies'; -import './Text.css'; +import styles from './Text.module.css'; const SearchResults = ({ results, displayedResults, isAuthorized }) => { let error = null; @@ -11,10 +11,10 @@ const SearchResults = ({ results, displayedResults, isAuthorized }) => { return (
{!error && ( -
-
+
+
{displayedResults.map((result, resultIndex) => ( -
+
{ const currentDate = new Date(); @@ -10,26 +10,28 @@ const MainCompanies = ({ companyData, isAuthorized }) => { const usersSavedList = []; return ( -
-
-
+
+
+
{companyData.name}
-
-
-
+
+
+
{companyData.categories && companyData.categories .map((category) => category.name) .join(' ')}
-
+
{companyData.name} @@ -37,13 +39,15 @@ const MainCompanies = ({ companyData, isAuthorized }) => {
-
+
{companyData.address}
-
-
-
-
+
+
+
+
{currentYear - companyData.founded} років досвіду
@@ -58,7 +62,7 @@ const MainCompanies = ({ companyData, isAuthorized }) => {
{/* if company added - del from saved list */}
-
-
+
+
{`${companyData.name}
diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.css b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css similarity index 100% rename from FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.css rename to FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css diff --git a/FrontEnd/src/components/SearchPage/search_page.css b/FrontEnd/src/components/SearchPage/search_page.module.css similarity index 100% rename from FrontEnd/src/components/SearchPage/search_page.css rename to FrontEnd/src/components/SearchPage/search_page.module.css From 5d1111afdbbbf8ef5c0f75fb027e4fbb405a42c5 Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Tue, 17 Oct 2023 15:43:52 +0300 Subject: [PATCH 07/18] delete styles from search_page --- FrontEnd/src/components/SearchPage/Search.js | 40 ++++++++++++------- .../SearchPage/search_page.module.css | 39 ------------------ 2 files changed, 25 insertions(+), 54 deletions(-) diff --git a/FrontEnd/src/components/SearchPage/Search.js b/FrontEnd/src/components/SearchPage/Search.js index c6c00ce3..7d3d033f 100644 --- a/FrontEnd/src/components/SearchPage/Search.js +++ b/FrontEnd/src/components/SearchPage/Search.js @@ -6,7 +6,7 @@ import SearchResults from './search_field/SearchResults'; import frame42 from './img/frame42.png'; import link_to_left from './img/link_to_left.svg'; import link_to_right from './img/link_to_right.svg'; -import './search_page.module.css'; +import styles from './search_page.module.css'; const ITEMS_PER_PAGE = 6; @@ -51,21 +51,23 @@ export function Search(props) { }; return ( -
+
-
- frame -
+
+ frame +
{searchResults && ( -

+

РЕЗУЛЬТАТІВ ЗА ПОШУКОМ{' '} - {searchTerm} :{' '} - {searchResults.length > 0 ? searchResults.length : 0} + + {searchTerm} + {' '} + : {searchResults.length > 0 ? searchResults.length : 0}

)}
-
+
{!error && searchResults.length > 0 ? ( <> ) : ( -

+

Пошук не дав результатів: компанії з іменем{' '} - + {searchTerm} {' '} не було виявлено на даний момент

)}
-
+
{totalPages > 1 && ( -
+
{currentPage > 1 && ( - {currentPage > 2 && ...} + {currentPage > 2 && ( + ... + )} )} {Array.from({ length: totalPages }, (_, i) => { @@ -121,7 +131,7 @@ export function Search(props) { {currentPage < totalPages - 1 && ( <> {currentPage < totalPages - 1 && ( - ... + ... )}
-
+
{companyData.categories && companyData.categories .map((category) => category.name) .join(' ')}
-
+
{
-
+
{companyData.address}
diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css index 67c637ee..12bb1f66 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css +++ b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css @@ -51,6 +51,7 @@ font-style: normal; font-weight: 700; line-height: 120%; /* 19.2px */ + text-align: left; } .product-card__name-text { width: 328px; @@ -62,6 +63,7 @@ font-weight: 700; line-height: 120%; /* 24px */ text-transform: uppercase; + text-align: left; } .product-card__name-text_link { @@ -83,6 +85,7 @@ font-weight: 400; line-height: 20px; /* 142.857% */ letter-spacing: -0.14px; + text-align: left; } .product-card__badges-block { width: 100%; @@ -145,10 +148,6 @@ position: absolute; } -.align_items_left { - text-align: left; -} - .product-card__buttons { color: var(--companies-card-button); border: none; diff --git a/FrontEnd/src/components/SearchPage/search_page.module.css b/FrontEnd/src/components/SearchPage/search_page.module.css index 8b09a611..67dd1f2c 100644 --- a/FrontEnd/src/components/SearchPage/search_page.module.css +++ b/FrontEnd/src/components/SearchPage/search_page.module.css @@ -2,6 +2,7 @@ .main_block_outer { padding-top: 10px; + width: 1512px; } .new-companies-main { @@ -15,7 +16,7 @@ .new-companies-search_count { display: flex; margin: auto; - padding-left: 7%; + padding-left: 10%; } .search_field_entered_value { @@ -36,10 +37,10 @@ font: Inter; } -.search_result_error_search_value { +/* .search_result_error_search_value { color: var(--main-style-signs-color); } - + */ .frame-img-right { position: absolute; top: 30px; From 38adb47fb94bf2f49f5a211aafa60055a19d0fea Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Tue, 17 Oct 2023 20:13:33 +0300 Subject: [PATCH 09/18] add enter-press --- .../src/components/HeaderFooter/header/navbar/SearchBox.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx index afb10fd5..af7c8222 100644 --- a/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx +++ b/FrontEnd/src/components/HeaderFooter/header/navbar/SearchBox.jsx @@ -23,6 +23,11 @@ function SearchBox() { type="text" placeholder="Пошук" onChange={(e) => setSearchTerm(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + handleSearch(searchTerm, searchPage); + } + }} />
diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css index 12bb1f66..73e14ba9 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css +++ b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css @@ -27,6 +27,7 @@ flex-shrink: 0; border-radius: 11px; object-fit: cover; + opacity: 0.5; } .product-card__text-block { display: flex; From 77bc8495311e632ca23484cfc2071b93305e3267 Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Wed, 18 Oct 2023 15:00:07 +0300 Subject: [PATCH 11/18] opacity --- .../SearchPage/search_field/companies/CompaniesCards.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css index 73e14ba9..edcfcb72 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css +++ b/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css @@ -27,7 +27,7 @@ flex-shrink: 0; border-radius: 11px; object-fit: cover; - opacity: 0.5; + opacity: 0.7; } .product-card__text-block { display: flex; From 72c3028d6f06aa813c0e742abe7c0c99f3338182 Mon Sep 17 00:00:00 2001 From: Sofia Bilous Date: Thu, 19 Oct 2023 21:11:21 +0300 Subject: [PATCH 12/18] stars, swr --- FrontEnd/src/App.js | 2 +- FrontEnd/src/components/SearchPage/Search.js | 61 +++---- .../SearchPage/search_field/SearchResults.js | 7 +- .../search_field/companies/Companies.js | 107 ------------- .../search_field/companies/CompanyCard.js | 151 ++++++++++++++++++ ...ards.module.css => CompanyCard.module.css} | 5 + .../src/components/basicPage/BasicPage.jsx | 10 +- 7 files changed, 191 insertions(+), 152 deletions(-) delete mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/Companies.js create mode 100644 FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.js rename FrontEnd/src/components/SearchPage/search_field/companies/{CompaniesCards.module.css => CompanyCard.module.css} (98%) diff --git a/FrontEnd/src/App.js b/FrontEnd/src/App.js index cbb52013..7b06606b 100644 --- a/FrontEnd/src/App.js +++ b/FrontEnd/src/App.js @@ -17,7 +17,7 @@ function App() { } /> } /> - } /> + } />
diff --git a/FrontEnd/src/components/SearchPage/Search.js b/FrontEnd/src/components/SearchPage/Search.js index 8b64fd5f..374ffa51 100644 --- a/FrontEnd/src/components/SearchPage/Search.js +++ b/FrontEnd/src/components/SearchPage/Search.js @@ -1,5 +1,6 @@ import axios from 'axios'; -// import { useSWRConfig } from 'swr'; +import { useSWRConfig } from 'swr'; +import useSWRMutation from 'swr/mutation'; import { useState, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import BreadCrumbs from '../BreadCrumbs/BreadCrumbs'; @@ -21,48 +22,36 @@ export function Search(props) { const searchTerm = searchParams.get('name'); const servedAddress = process.env.REACT_APP_BASE_API_URL; const searchUrl = 'search'; + const { mutate } = useSWRConfig(); - // useEffect(() => { - // if (searchTerm) { - // // Make an AJAX request to Django API to get search results - // axios - // .get(`${servedAddress}/api/search/?name=${searchTerm}`) - // .then((response) => { - // setSearchResults(response.data); - // setSearchPerformed(true); - // setError(null); // Clear error on successful response - // }) - // .catch((error) => { - // console.error('Error fetching search results:', error); - // setError(error.response ? error.response.data : 'An error occurred'); - // }); - // } - // }, [searchTerm, servedAddress, searchUrl]); + const fetcher = (url) => axios.get(url).then((res) => res.data); + + async function getRequest(url) { + const data = await fetcher(url); + setSearchResults(data); + setSearchPerformed(true); + setError(null); + } + + const { trigger } = useSWRMutation( + `${servedAddress}/api/search/?name=${searchTerm}`, + getRequest + ); + + mutate((key) => typeof key === 'string' && key.startsWith('/api/search/'), { + revalidate: true, + }); useEffect(() => { if (searchTerm) { - // Make an AJAX request to Django API to get search results - axios - .get(`${servedAddress}/api/search/?name=${searchTerm}`) - .then((response) => { - setSearchResults(response.data); - setSearchPerformed(true); - setError(null); // Clear error on successful response - }) - .catch((error) => { - console.error('Error fetching search results:', error); - setError(error.response ? error.response.data : 'An error occurred'); - }); + try { + trigger(); + } catch (error) { + console.error(error); + } } }, [searchTerm, servedAddress, searchUrl]); - // const fetcher = url => axios.get(url).then(res => res.data) - - // function fetchSearchResults () { - // const { data, error } = useSWR('/api/data', fetcher) - // // ... - // } - const [currentPage, setCurrentPage] = useState(1); const totalItems = searchResults.length; const totalPages = Math.ceil(totalItems / ITEMS_PER_PAGE); diff --git a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js index a812d07e..8f51981e 100644 --- a/FrontEnd/src/components/SearchPage/search_field/SearchResults.js +++ b/FrontEnd/src/components/SearchPage/search_field/SearchResults.js @@ -1,4 +1,4 @@ -import MainCompanies from './companies/Companies'; +import CompanyCard from './companies/CompanyCard'; import styles from './Text.module.css'; const SearchResults = ({ results, displayedResults, isAuthorized }) => { @@ -15,10 +15,7 @@ const SearchResults = ({ results, displayedResults, isAuthorized }) => {
{displayedResults.map((result, resultIndex) => (
- +
))}
diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js b/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js deleted file mode 100644 index 030c3542..00000000 --- a/FrontEnd/src/components/SearchPage/search_field/companies/Companies.js +++ /dev/null @@ -1,107 +0,0 @@ -import { Link } from 'react-router-dom'; -import wish_list_checklist from './img/wish_list_checklist.svg'; -import wish_list_checklist_added from './img/wish_list_checklist_added.svg'; -import styles from './CompaniesCards.module.css'; - -const MainCompanies = ({ companyData, isAuthorized }) => { - const currentDate = new Date(); - const currentYear = currentDate.getFullYear(); - - const usersSavedList = []; - const yearsOfExperiense = companyData.founded - ? currentYear - companyData.founded - : 0; - - return ( -
-
-
- {companyData.name} -
-
-
-
- {companyData.categories && - companyData.categories - .map((category) => category.name) - .join(' ')} -
-
- - {companyData.name} - -
-
-
-
- {companyData.address} -
-
-
-
-
- {yearsOfExperiense} років досвіду -
-
-
- - {/* if user is authorized - show add to favorite button*/} - {isAuthorized === true && ( - <> - {/* Add checking if company is in user list */} - {usersSavedList.includes(companyData.id) ? ( - <> -
- {/* if company added - del from saved list */} - -
- - ) : ( - <> -
- {/* if compony not added - add to saved list */} - -
- - )} - - )} -
-
-
-
-
- - {/* {`${companyData.name} */} -
-
-
- ); -}; - -export default MainCompanies; diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.js b/FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.js new file mode 100644 index 00000000..a2d57a38 --- /dev/null +++ b/FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.js @@ -0,0 +1,151 @@ +import { Link } from 'react-router-dom'; +import { StarOutlined, StarFilled } from '@ant-design/icons'; +import { useState, useEffect } from 'react'; +import { useSWRConfig } from 'swr'; +import useSWRMutation from 'swr/mutation'; +// import useSWR from 'swr'; +import axios from 'axios'; +import styles from './CompanyCard.module.css'; + +const CompanyCard = ({ companyData, isAuthorized }) => { + const { mutate } = useSWRConfig(); + const authToken = localStorage.getItem('Token'); + const currentDate = new Date(); + const currentYear = currentDate.getFullYear(); + const yearsOfExperiense = companyData.founded + ? currentYear - companyData.founded + : 0; + const [usersSavedList, setUsersSavedList] = useState([]); + const [star, setStar] = useState(false); + const [isSaved, setIsSaved] = useState(false); + + async function sendRequest(url, { arg: data }) { + return fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Token ${authToken}`, + }, + body: JSON.stringify(data), + }).then(); + } + + const { trigger } = useSWRMutation( + `${process.env.REACT_APP_BASE_API_URL}/api/saved-list/`, + sendRequest + ); + + const handleClick = async () => { + try { + await trigger( + { company_pk: companyData.id }, + { optimisticData: () => setIsSaved(!isSaved) } + ); + } catch (error) { + console.error(error); + } + }; + + mutate((key) => typeof key === 'string' && key.startsWith('/api/profiles/'), { + revalidate: true, + }); + + const filledStar = ( + + ); + const outlinedStar = ( + + ); + + useEffect(() => { + if (isAuthorized) + axios + .get( + `${process.env.REACT_APP_BASE_API_URL}/api/profiles/?is_saved=True`, + { + withCredentials: true, + headers: { + Authorization: 'Token ' + authToken, + }, + } + ) + .then((response) => { + const NewList = []; + for (let item of response.data.results) { + NewList.push(item['id']); + } + + setUsersSavedList(NewList); + if (usersSavedList.includes(companyData.id)) { + setStar(filledStar); + setIsSaved(true); + } else { + setIsSaved(false); + setStar(outlinedStar); + } + }) + .catch((error) => { + console.error('Error fetching search results:', error); + }); + }, [usersSavedList]); + + return ( +
+
+
+ {companyData.name} +
+
+
+
+ {companyData.categories && + companyData.categories + .map((category) => category.name) + .join(' ')} +
+
+ + {companyData.name} + +
+
+
+
+ {companyData.address} +
+
+
+
+
+ {yearsOfExperiense} років досвіду +
+
+
+ {/* {isAuthorized ? (isSaved ? filledStar : outlinedStar) : null} */} + {star} + {/*
{}
*/} +
+
+
+
+
+ +
+
+
+ ); +}; + +export default CompanyCard; diff --git a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css b/FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.module.css similarity index 98% rename from FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css rename to FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.module.css index edcfcb72..a98db543 100644 --- a/FrontEnd/src/components/SearchPage/search_field/companies/CompaniesCards.module.css +++ b/FrontEnd/src/components/SearchPage/search_field/companies/CompanyCard.module.css @@ -158,3 +158,8 @@ .product-card__buttons:hover { cursor: pointer; } + +.star { + color: #ffd800; + font-size: 24px; +} diff --git a/FrontEnd/src/components/basicPage/BasicPage.jsx b/FrontEnd/src/components/basicPage/BasicPage.jsx index 71f9d1a0..195d5e7d 100644 --- a/FrontEnd/src/components/basicPage/BasicPage.jsx +++ b/FrontEnd/src/components/basicPage/BasicPage.jsx @@ -14,7 +14,7 @@ import { SignUpPage } from '../SignUp/pages/SignUpPage'; import ScrollToTopButton from '../PrivacyPolicyPage/privacy/ScrollToTopButton'; import TermsAndConditions from '../terms-and-conditions-app/terms_conditions/TermsAndConditionsComponent'; import { useAuth } from '../../hooks'; - +import { Search } from '../SearchPage/Search'; function BasicPage() { const auth = useAuth(); @@ -56,7 +56,10 @@ function BasicPage() { } /> } /> - }/> + } + /> {auth.isAuth ? ( } /> ) : ( @@ -66,10 +69,11 @@ function BasicPage() { } /> } /> } /> + } />