diff --git a/BackEnd/forum/pagination.py b/BackEnd/forum/pagination.py index 13181cc3c..a6158a910 100644 --- a/BackEnd/forum/pagination.py +++ b/BackEnd/forum/pagination.py @@ -3,9 +3,15 @@ class ForumPagination(PageNumberPagination): - page_size = 6 + page_size = 16 page_size_query_param = "page_size" - max_page_size = 18 + max_page_size = 64 + + def get_page_number(self, request, paginator): + page_number = super().get_page_number(request, paginator) + if int(page_number) > paginator.num_pages: + page_number = paginator.num_pages or 1 + return page_number def get_paginated_response(self, data): return Response( diff --git a/BackEnd/profiles/tests/test_new_members.py b/BackEnd/profiles/tests/test_new_members.py index eb130e7e4..723e42bdd 100644 --- a/BackEnd/profiles/tests/test_new_members.py +++ b/BackEnd/profiles/tests/test_new_members.py @@ -137,22 +137,6 @@ def setUp(self) -> None: self.company_dnipro.created_at = utc_datetime(2023, 12, 2) self.company_dnipro.save() - self.company_kharkiv = ProfileStartupFactory( - name="Kharkiv", - person=self.kharkiv_user, - completeness=1, - ) - self.company_kharkiv.created_at = utc_datetime(2023, 12, 3) - self.company_kharkiv.save() - - self.company_chernigiv = ProfileStartupFactory( - name="Chernigiv", - person=self.chernigiv_user, - completeness=1, - ) - self.company_chernigiv.created_at = utc_datetime(2023, 12, 4) - self.company_chernigiv.save() - self.company_kirovohrad = ProfileCompanyFactory( name="Kirovohrad", person=self.kirovohrad_user, @@ -163,17 +147,17 @@ def setUp(self) -> None: def test_get_less_companies(self): response = self.client.get( - path="/api/profiles/?ordering=-completeness,-created_at" + path="/api/profiles/?ordering=-completeness,-created_at&page_size=4" ) names_from_response = [ prof["name"] for prof in response.data["results"] ] self.assertEqual( - ["Kirovohrad", "Dnipro", "Kyiv", "Chernigiv", "Kharkiv"], + ["Kirovohrad", "Dnipro", "Kyiv"], names_from_response, ) self.assertEqual(200, response.status_code) - self.assertEqual(5, response.data["total_items"]) + self.assertEqual(3, response.data["total_items"]) self.assertEqual(1, response.data["current"]) self.assertEqual(1, response.data["total_pages"]) self.assertEqual(None, response.data["next"]) @@ -187,7 +171,7 @@ def test_get_enough_companies(self): self.company_synelnicovo.created_at = utc_datetime(2023, 12, 7) self.company_synelnicovo.save() response = self.client.get( - path="/api/profiles/?ordering=-completeness,-created_at" + path="/api/profiles/?ordering=-completeness,-created_at&page_size=4" ) self.assertEqual(200, response.status_code) names_from_response = [ @@ -200,12 +184,10 @@ def test_get_enough_companies(self): "Kirovohrad", "Dnipro", "Kyiv", - "Chernigiv", - "Kharkiv", ], names_from_response, ) - self.assertEqual(6, response.data["total_items"]) + self.assertEqual(4, response.data["total_items"]) self.assertEqual(1, response.data["current"]) self.assertEqual(1, response.data["total_pages"]) self.assertEqual(None, response.data["next"]) @@ -228,20 +210,20 @@ def test_get_more_companies(self): self.company_odesa.save() response = self.client.get( - path="/api/profiles/?ordering=-completeness,-created_at" + path="/api/profiles/?ordering=-completeness,-created_at&page_size=4" ) names_from_response = [ prof["name"] for prof in response.data["results"] ] self.assertEqual( - ["Odesa", "Mykolaiv", "Kirovohrad", "Dnipro", "Kyiv", "Chernigiv"], + ["Odesa", "Mykolaiv", "Kirovohrad", "Dnipro"], names_from_response, ) self.assertEqual(200, response.status_code) - self.assertEqual(7, response.data["total_items"]) + self.assertEqual(5, response.data["total_items"]) self.assertEqual(1, response.data["current"]) self.assertEqual(2, response.data["total_pages"]) self.assertEqual( - "http://testserver/api/profiles/?ordering=-completeness%2C-created_at&page=2", + "http://testserver/api/profiles/?ordering=-completeness%2C-created_at&page=2&page_size=4", response.data["next"], ) diff --git a/BackEnd/profiles/tests/test_ordering.py b/BackEnd/profiles/tests/test_ordering.py index 6bc36057a..0b410f0fe 100644 --- a/BackEnd/profiles/tests/test_ordering.py +++ b/BackEnd/profiles/tests/test_ordering.py @@ -156,8 +156,8 @@ def test_get_list_of_profiles_completeness_order_asc(self): self.assertEqual(status.HTTP_200_OK, response.status_code) self.assertEqual( [ - "Winery", "Bakery", + "Winery", "Delivery company", "Catering service", "Retail company", diff --git a/FrontEnd/package-lock.json b/FrontEnd/package-lock.json index bb9aad578..6d4200ac0 100644 --- a/FrontEnd/package-lock.json +++ b/FrontEnd/package-lock.json @@ -17641,7 +17641,6 @@ "version": "0.20.0", "resolved": "https://registry.npmjs.org/react-highlight-words/-/react-highlight-words-0.20.0.tgz", "integrity": "sha512-asCxy+jCehDVhusNmCBoxDf2mm1AJ//D+EzDx1m5K7EqsMBIHdZ5G4LdwbSEXqZq1Ros0G0UySWmAtntSph7XA==", - "license": "MIT", "dependencies": { "highlight-words-core": "^1.2.0", "memoize-one": "^4.0.0", diff --git a/FrontEnd/public/favicon-16x16.png b/FrontEnd/public/favicon-16x16.png index 9839240bb..14c58dcad 100644 Binary files a/FrontEnd/public/favicon-16x16.png and b/FrontEnd/public/favicon-16x16.png differ diff --git a/FrontEnd/public/favicon-32x32.png b/FrontEnd/public/favicon-32x32.png index 71ddb1293..c71d92a98 100644 Binary files a/FrontEnd/public/favicon-32x32.png and b/FrontEnd/public/favicon-32x32.png differ diff --git a/FrontEnd/public/favicon.ico b/FrontEnd/public/favicon.ico index 63eabdcfd..bd10115ab 100644 Binary files a/FrontEnd/public/favicon.ico and b/FrontEnd/public/favicon.ico differ diff --git a/FrontEnd/public/forum-logo.ico b/FrontEnd/public/forum-logo.ico deleted file mode 100644 index 62bea69b4..000000000 Binary files a/FrontEnd/public/forum-logo.ico and /dev/null differ diff --git a/FrontEnd/public/img/cookies.png b/FrontEnd/public/img/cookies.png new file mode 100644 index 000000000..530b9351b Binary files /dev/null and b/FrontEnd/public/img/cookies.png differ diff --git a/FrontEnd/public/img/main-baner.png b/FrontEnd/public/img/main-baner.png new file mode 100644 index 000000000..08b8ffbb0 Binary files /dev/null and b/FrontEnd/public/img/main-baner.png differ diff --git a/FrontEnd/public/svg/arrow-down.svg b/FrontEnd/public/svg/arrow-down.svg new file mode 100644 index 000000000..96d156440 --- /dev/null +++ b/FrontEnd/public/svg/arrow-down.svg @@ -0,0 +1,3 @@ + diff --git a/FrontEnd/public/svg/arrow-up.svg b/FrontEnd/public/svg/arrow-up.svg new file mode 100644 index 000000000..224c57140 --- /dev/null +++ b/FrontEnd/public/svg/arrow-up.svg @@ -0,0 +1,3 @@ + diff --git a/FrontEnd/public/svg/empty-decore-31x29.svg b/FrontEnd/public/svg/empty-decore-31x29.svg new file mode 100644 index 000000000..40424cdff --- /dev/null +++ b/FrontEnd/public/svg/empty-decore-31x29.svg @@ -0,0 +1,23 @@ + diff --git a/FrontEnd/public/svg/empty-decore-50x46.svg b/FrontEnd/public/svg/empty-decore-50x46.svg new file mode 100644 index 000000000..3eb189b20 --- /dev/null +++ b/FrontEnd/public/svg/empty-decore-50x46.svg @@ -0,0 +1,23 @@ + diff --git a/FrontEnd/src/App.css b/FrontEnd/src/App.css index e5d392976..4066ac164 100644 --- a/FrontEnd/src/App.css +++ b/FrontEnd/src/App.css @@ -7,4 +7,4 @@ body { width: 100vw; -} \ No newline at end of file +} diff --git a/FrontEnd/src/components/CompanyCard/CompanyCard.jsx b/FrontEnd/src/components/CompanyCard/CompanyCard.jsx index 00f1e77c7..7870c6d03 100644 --- a/FrontEnd/src/components/CompanyCard/CompanyCard.jsx +++ b/FrontEnd/src/components/CompanyCard/CompanyCard.jsx @@ -1,4 +1,5 @@ import { Link } from 'react-router-dom'; +import { mutate } from 'swr'; import styles from './CompanyCard.module.css'; import { useAuth } from '../../hooks'; import PropTypes from 'prop-types'; @@ -45,6 +46,11 @@ export default function CompanyCard({ changeCompanies(profile.id, false); try { await axios.delete(`${process.env.REACT_APP_BASE_API_URL}/api/saved-list/${profile.id}`); + await mutate( + (key) => typeof key === 'string' && key.includes('/api/profiles/?is_saved=True'), + undefined, + {revalidate: true} + ); } catch (error) { console.error(error); } diff --git a/FrontEnd/src/components/CompanyCard/CompanyCard.module.css b/FrontEnd/src/components/CompanyCard/CompanyCard.module.css index 81a5137c9..0cb137dfd 100644 --- a/FrontEnd/src/components/CompanyCard/CompanyCard.module.css +++ b/FrontEnd/src/components/CompanyCard/CompanyCard.module.css @@ -2,11 +2,11 @@ width: 345px; height: 365px; display: block; - align-items: center; border-radius: 11px; position: relative; margin: auto; background: var(--company-card-color); + box-shadow: 0px 0px 2px 0px #41404533; } .company-card:hover { @@ -80,7 +80,8 @@ text-align: left; padding-left: 16px; padding-top: 6px; - max-width: 300px; + max-width: 262px; + height: 35px; } .company-card__name-text { @@ -152,7 +153,7 @@ height: 50px; background: var(--company-card-color); border-radius: 9999px; - border: 2px solid #232424; + border: 1px solid var(--grey-border-color); } .company-card__logo-image { @@ -169,7 +170,8 @@ bottom: 13px; } -@media only screen and (min-width: 1200px) { +@media only screen and (min-width: 1512px) { + .company-card, .company-card__image-frame, .company-card__image, @@ -180,7 +182,8 @@ .company-card__star { left: 256px; } + .company-card__category-text { - max-width: 250px; + max-width: 220px; } -} \ No newline at end of file +} diff --git a/FrontEnd/src/components/CookieAcception/CookieMod.jsx b/FrontEnd/src/components/CookieAcception/CookieMod.jsx index adeb74350..8821e613a 100644 --- a/FrontEnd/src/components/CookieAcception/CookieMod.jsx +++ b/FrontEnd/src/components/CookieAcception/CookieMod.jsx @@ -1,81 +1,164 @@ -import { Link } from 'react-router-dom'; +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; import { useCookies } from 'react-cookie'; +import { Link } from 'react-router-dom'; import styles from './CookieMod.module.css'; -import { useState } from 'react'; const CookieMod = ({ active, setActive }) => { - const [cookies, setCookie] = useCookies(); + const [cookies, setCookie] = useCookies(['necessary', 'statistics', 'preferences', 'marketing']); const [detailsVisible, setDetailsVisible] = useState(false); const accessCookie = () => { const d = new Date(); - const cookieLifeTime = 30 * 24 * 60 * 60 * 1000; - d.setTime(d.getTime() + cookieLifeTime); - setCookie('first', true, { expires: d, sameSite: 'lax' }); - setActive(false); - }; - - const denyCookie = () => { - const d = new Date(); - const cookieLifeTime = 30 * 24 * 60 * 60 * 1000; - d.setTime(d.getTime() + cookieLifeTime); - setCookie('first', false, { expires: d, sameSite: 'lax' }); + d.setTime(d.getTime() + 30 * 24 * 60 * 60 * 1000); + setCookie('necessary', true, { expires: d, sameSite: 'lax' }); + setCookie('statistics', true, { expires: d, sameSite: 'lax' }); + setCookie('preferences', true, { expires: d, sameSite: 'lax' }); + setCookie('marketing', true, { expires: d, sameSite: 'lax' }); setActive(false); }; - const toggleDetails = (event) => { - event.preventDefault(); + const toggleDetails = () => { setDetailsVisible(!detailsVisible); }; - return cookies.first ? null : ( -
- Наш веб-сайт використовує файли cookie, щоб покращити ваш досвід. Ви - можете відмовитися, якщо хочете. Дізнатися більше{' '} - { - - про кукі-файли + return active ? ( +
+ Наш веб-сайт використовує файли cookie, щоб покращити ваш досвід. +
++ Дізнатися більше + + про файли cookies. - } - -
- {detailsVisible && ( -Використання файлів "cookies"
-- 1. Файли "cookies" є невеликими текстовими файлами, які можуть бути розміщені на пристрої - користувача під час відвідування Сайту. Вони дозволяють збирати та зберігати певну інформацію про - відвідувачів, таку як налаштування мови, історія перегляду, дані автентифікації та інші деталі. - Використання файлів "cookies" на Сайті сприяє поліпшенню зручності та персоналізації досвіду - користувачів, дозволяючи зберігати інформацію про їхній вибір та взаємодію з різними елементами Сайту. -
-- 2. Користувач має можливість керувати використанням файлів "cookies" у налаштуваннях свого - веб-браузера. Відключення файлів "cookies" може бути здійснено користувачем у будь-який - момент. Проте важливо зауважити, що відключення "cookies" може призвести до обмеження - функціональності Сайту, а також до втрати певних персоналізованих налаштувань та зручностей, які вони - забезпечують. -
+ ++ Файли "cookies" є невеликими текстовими файлами, які можуть бути розміщені на + пристрої користувача під час відвідування Сайту. Вони дозволяють збирати та зберігати певну + інформацію про відвідувачів, таку як налаштування мови, історія перегляду, дані + автентифікації та інші деталі. Використання файлів "cookies" на Сайті сприяє + поліпшенню зручності та персоналізації досвіду користувачів, дозволяючи зберігати інформацію + про їхній вибір та взаємодію з різними елементами Сайту. +
++ Your permission applies to the following domains: +
++ Necessary cookies help make a website usable by enabling basic functions like page + navigation and access to secure areas of the website. The website cannot function properly + without these cookies. +
++ Statistic cookies help website owners understand how visitors interact with websites by + collecting and reporting information anonymously. +
++ Preference cookies enable a website to remember information that changes the way the + website behaves or looks, like your preferred language or the region that you are in. +
++ Marketing cookies are used to track visitors across websites. The intention is to display + ads that are relevant and engaging for the individual user and thereby more valuable for + publishers and third-party advertisers. +
+{linkText} @@ -59,7 +59,7 @@ const MainCompanies = ({ isAuthorized }) => {
Про компанію
-Конкурентна перевага
-Візія, слоган
-{slogan}
-Формат співпраці
-{key}
-- {value} -
-{key}
- {value.map((contact, index) => { - if (contact.url) { - return ( - - {contact.svgPath} - - ); - } - return null; - })} -{key}
-{value}
-{key}
+{value}
+{key}
+ {value.map((contact, index) => { + if (contact.url) { + return ( + + {contact.svgPath} + + ); + } + return null; + })} +{key}
+{value}
+- {profileData.phone} - { - profileData.phone ? copyContent('phone')}> - {renderIcons(isPhoneCopied)} - - : null - } + {(profileData.phone) ? ('+' + profileData.phone) : ''} + { + profileData.phone ? copyContent('phone')}> + {renderIcons(isPhoneCopied)} + + : null + }
- {profileData.email.length > LENGTH_EMAIL ? (
+ {profileData.email.length > LENGTH_EMAIL ? (
+ Інформація не заповнена +
+Логістика товарів / послуг
-{key}
-- Інформація не заповнена -
-- {profile.activities} -
-- {profile.regions} -
-+ {profile.activities} +
++ {profile.regions} +
+- {profile.activities} -
-{number}
-{getCompanyWord(number)}
-{number} {getCompanyWord(number)}
+Це призведе до остаточного видалення всіх ваших даних про компанію чи стартап й також включно з списком сподобаних профілів.
+Для видалення вашого профілю введіть вашу електронну пошту та пароль.
+ Ця дія не може бути відміненою!