From 389acc1b7dabb668e4947c1990212e940e2cd569 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 01:46:06 +0300 Subject: [PATCH 01/11] some corrections w.r.t exhibitions and css improvements --- .../src/components/HomeGalleryCard.js | 69 +++++++++++++++---- App/frontend/src/components/LoginModal.js | 9 ++- App/frontend/src/components/SignupModal.js | 2 +- App/frontend/src/components/styles/Access.css | 9 +++ App/frontend/src/pages/Profile.js | 6 +- App/frontend/src/pages/SearchResults.js | 4 +- 6 files changed, 78 insertions(+), 21 deletions(-) diff --git a/App/frontend/src/components/HomeGalleryCard.js b/App/frontend/src/components/HomeGalleryCard.js index 299a9de9..ec0f947e 100644 --- a/App/frontend/src/components/HomeGalleryCard.js +++ b/App/frontend/src/components/HomeGalleryCard.js @@ -25,8 +25,7 @@ function HomeGalleryCard(props) { return ( <>
-
Discover Exhibitions
-
navigate(`/users/${1}`)}>TEST PROFILE
+
Featured Art Items
goToArtItem(1)} @@ -34,61 +33,105 @@ function HomeGalleryCard(props) { name="Lost Highway" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={buddhists} name="Four Noble Truths" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={haybales} name="Agriculture in the Netherlands" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={wheat} name="Fauvism" />
goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={greenFace} name="To Pimp a Butterfly" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={greenFood} name="Green Life" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={greenCadillac} name="1957 Cadillac Eldorado Biarritz " /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={angel} name="Forgotten Statues" />
goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={cyber} name="One Night in Shangai" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={bluebuilding} name="Architecture in Movies" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={rome} name="Rome: A History of the Eternal City" /> goToArtItem(13)*/}} + onClick={ + { + /*() => goToArtItem(13)*/ + } + } source={beach} name="West Coast" /> diff --git a/App/frontend/src/components/LoginModal.js b/App/frontend/src/components/LoginModal.js index 8679122d..6c0bcb79 100644 --- a/App/frontend/src/components/LoginModal.js +++ b/App/frontend/src/components/LoginModal.js @@ -130,10 +130,15 @@ function Login(props) {

- Forgot password? + + Forgot password? +

- Not on Artopia yet? Sign up + Not on Artopia yet?{" "} + + Sign up +

diff --git a/App/frontend/src/components/SignupModal.js b/App/frontend/src/components/SignupModal.js index 0b932753..b30a7c52 100644 --- a/App/frontend/src/components/SignupModal.js +++ b/App/frontend/src/components/SignupModal.js @@ -77,7 +77,7 @@ function Signup(props) {

Sign Up

- Already registered? Log in + Already registered? Log in
diff --git a/App/frontend/src/components/styles/Access.css b/App/frontend/src/components/styles/Access.css index df195a71..260dd511 100644 --- a/App/frontend/src/components/styles/Access.css +++ b/App/frontend/src/components/styles/Access.css @@ -46,3 +46,12 @@ margin-bottom: 0px; margin-right: 15px; /* padding-top-form (10) + margin-top-btn(5)*/ } + +.access-link { + color: #3483be; +} + +.access-link:hover, +.access-link:active { + color: #3483be; +} diff --git a/App/frontend/src/pages/Profile.js b/App/frontend/src/pages/Profile.js index 54462344..b41bf872 100644 --- a/App/frontend/src/pages/Profile.js +++ b/App/frontend/src/pages/Profile.js @@ -171,8 +171,7 @@ function Profile(props) { ]); useEffect(() => { - // BURA DEGISECEK - fetch(`${host}/api/v1/exhibitions/users/2/online/`, { + fetch(`${host}/api/v1/exhibitions/me/`, { method: "GET", headers: { "Content-Type": "application/json", @@ -181,7 +180,8 @@ function Profile(props) { }) .then((response) => response.json()) .then((response) => { - // console.log(response.length); + console.log(response["Virtual Exhibitions"]); + response = response["Virtual Exhibitions"].owner; var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; var online_exhibitions = []; diff --git a/App/frontend/src/pages/SearchResults.js b/App/frontend/src/pages/SearchResults.js index 6fea182f..0f002394 100644 --- a/App/frontend/src/pages/SearchResults.js +++ b/App/frontend/src/pages/SearchResults.js @@ -60,7 +60,7 @@ function SearchResults(props) { setArtItemPaths(art_item_paths); }) .catch((error) => console.error("Error:", error)); - }, [host]); + }, [host, tag_id]); useEffect(() => { fetch(`${host}/api/v1/tags/${tag_id}`, { @@ -74,7 +74,7 @@ function SearchResults(props) { setTagName(response.tagname); }) .catch((error) => console.error("Error:", error)); - }, [host]); + }, [host, tag_id]); function goToArtItem(id) { navigate(`/artitems/${id}`); From 689d1bc4b1c9fa779bd482c198144b5d0aa6f9e2 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 02:13:05 +0300 Subject: [PATCH 02/11] handled search bar input changes --- App/frontend/src/components/Searchbar.js | 13 ++++++++++++- App/frontend/src/layout/Layout.js | 19 ------------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/App/frontend/src/components/Searchbar.js b/App/frontend/src/components/Searchbar.js index 041cfc55..63d1f12f 100644 --- a/App/frontend/src/components/Searchbar.js +++ b/App/frontend/src/components/Searchbar.js @@ -1,9 +1,18 @@ +import { useState } from "react"; import InputGroup from "react-bootstrap/InputGroup"; import Form from "react-bootstrap/Form"; import { AiOutlineSearch } from "react-icons/ai"; import "./styles/Searchbar.css"; function Searchbar() { + const [input, setInput] = useState(""); + + function handleInput(e) { + setInput(e.target.value); + } + + console.log(input); + return ( @@ -11,9 +20,11 @@ function Searchbar() { handleInput(e)} /> ); diff --git a/App/frontend/src/layout/Layout.js b/App/frontend/src/layout/Layout.js index 343cdce3..e8a95596 100644 --- a/App/frontend/src/layout/Layout.js +++ b/App/frontend/src/layout/Layout.js @@ -119,23 +119,6 @@ function Layout(props) { return () => window.removeEventListener("scroll", changeNavbarColor); }, []); - /*// keeps track of the current position of the scrollbar - function updatePosition() { - setCurrentScrollY(window.scrollY); - } - - useEffect(() => { - window.addEventListener("scroll", updatePosition); - return () => window.removeEventListener("scroll", updatePosition); - }, []); - - // prevents scrollbar to reset each time a component re-renders - useEffect(() => { - window.scrollTo(0, currentScrollY); - }, [currentScrollY]);*/ - - // keeps track of the current windows width - function updateWidth() { setWindowWidth(window.innerWidth); } @@ -145,8 +128,6 @@ function Layout(props) { return () => window.removeEventListener("resize", updateWidth); }, []); - // console.log(windowWidth); - return (
{token ? ( From cfb153a7b46fbce6477016ca4692847b3b3765ba Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 03:23:22 +0300 Subject: [PATCH 03/11] fixed recommendation poster issue --- App/frontend/src/components/Searchbar.js | 2 -- .../src/components/UploadOnlineExhibitionCard.js | 9 --------- App/frontend/src/pages/Exhibition.js | 1 - App/frontend/src/pages/Profile.js | 1 - App/frontend/src/pages/Recommendation.js | 10 +++++----- .../pages/RecommendedPages/RecommendedExhibitions.js | 10 +++++----- 6 files changed, 10 insertions(+), 23 deletions(-) diff --git a/App/frontend/src/components/Searchbar.js b/App/frontend/src/components/Searchbar.js index 63d1f12f..4602d8dd 100644 --- a/App/frontend/src/components/Searchbar.js +++ b/App/frontend/src/components/Searchbar.js @@ -11,8 +11,6 @@ function Searchbar() { setInput(e.target.value); } - console.log(input); - return ( diff --git a/App/frontend/src/components/UploadOnlineExhibitionCard.js b/App/frontend/src/components/UploadOnlineExhibitionCard.js index 6d6e22ab..f3caa16f 100644 --- a/App/frontend/src/components/UploadOnlineExhibitionCard.js +++ b/App/frontend/src/components/UploadOnlineExhibitionCard.js @@ -140,15 +140,6 @@ function UploadOnlineExhibitionCard(props) { } else if (title === "" || description === "" || posterPreview === "") { props.setUploadInfoError(true); } else { - const temp = base64Images.map((base64) => ({ - title: title, - description: `This art item is part of the ${title} exhibition and was uploaded exclusively for this exhibition`, - tags: [], - category: "OT", - artitem_image: base64, - })); - - console.log(temp); setIsLoading(true); fetch(`${host}/api/v1/exhibitions/me/online/`, { method: "POST", diff --git a/App/frontend/src/pages/Exhibition.js b/App/frontend/src/pages/Exhibition.js index f84cbf30..5bb59da7 100644 --- a/App/frontend/src/pages/Exhibition.js +++ b/App/frontend/src/pages/Exhibition.js @@ -85,7 +85,6 @@ function Exhibition(props) { .then((response) => response.json()) .then((response) => { var artitem_gallery_ids = response.artitems_gallery.map(({ id }) => id); - console.log(response.artitems_upload); var artitem_upload_ids = response.artitems_upload.map(({ id }) => id); var exhibition_ids = artitem_gallery_ids.concat(artitem_upload_ids); diff --git a/App/frontend/src/pages/Profile.js b/App/frontend/src/pages/Profile.js index b41bf872..31b850ee 100644 --- a/App/frontend/src/pages/Profile.js +++ b/App/frontend/src/pages/Profile.js @@ -180,7 +180,6 @@ function Profile(props) { }) .then((response) => response.json()) .then((response) => { - console.log(response["Virtual Exhibitions"]); response = response["Virtual Exhibitions"].owner; var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; diff --git a/App/frontend/src/pages/Recommendation.js b/App/frontend/src/pages/Recommendation.js index 1cd6d0f6..1d35d4f1 100644 --- a/App/frontend/src/pages/Recommendation.js +++ b/App/frontend/src/pages/Recommendation.js @@ -87,20 +87,20 @@ function Recommendation(props) { setExhibitionInfos(response.exhibitions); var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; - var exhibition_paths = []; + var exhibition_posters = []; for (let i = 0; i < response.exhibitions.length; i++) { var params = { Bucket: bucket, - Key: response.exhibitions[i].artitem_path, + Key: response.exhibitions[i].poster.artitem_path, }; var artitem_url = s3.getSignedUrl("getObject", params); - exhibition_paths.push(artitem_url); + exhibition_posters.push(artitem_url); } - setExhibitionPaths(exhibition_paths); + setExhibitionPaths(exhibition_posters); }) .catch((error) => console.error("Error:", error)); }, [host]); @@ -220,7 +220,7 @@ function Recommendation(props) {
- {exhibitionInfos.length!==0 ? ( + {exhibitionInfos.length !== 0 ? (
{exhibitionInfos.slice(0, 5).map((val, index) => { return ( diff --git a/App/frontend/src/pages/RecommendedPages/RecommendedExhibitions.js b/App/frontend/src/pages/RecommendedPages/RecommendedExhibitions.js index 510190d2..a40afb6c 100644 --- a/App/frontend/src/pages/RecommendedPages/RecommendedExhibitions.js +++ b/App/frontend/src/pages/RecommendedPages/RecommendedExhibitions.js @@ -40,7 +40,7 @@ function RecommendedExhibitions(props) { method: "GET", headers: { "Content-Type": "application/json", - Authorization: `Token ${token}`, + Authorization: `Token ${token}`, }, }) .then((response) => response.json()) @@ -49,20 +49,20 @@ function RecommendedExhibitions(props) { setExhibitionInfos(response.exhibitions); var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; - var exhibition_paths = []; + var exhibition_posters = []; for (let i = 0; i < response.exhibitions.length; i++) { var params = { Bucket: bucket, - Key: response.exhibitions[i].artitem_path, + Key: response.exhibitions[i].poster.artitem_path, }; var artitem_url = s3.getSignedUrl("getObject", params); - exhibition_paths.push(artitem_url); + exhibition_posters.push(artitem_url); } - setExhibitionPaths(exhibition_paths); + setExhibitionPaths(exhibition_posters); }) .catch((error) => console.error("Error:", error)); }, [host]); From b24823287343ad77e7da21052e37bbdb1fb7499f Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 04:14:25 +0300 Subject: [PATCH 04/11] changed searchResults to searchResultsTag --- App/backend/api/views/recommendation.py | 1 + App/frontend/src/App.js | 4 +- App/frontend/src/components/Searchbar.js | 12 +-- App/frontend/src/layout/Layout.js | 2 + App/frontend/src/pages/ArtItem.js | 4 +- App/frontend/src/pages/SearchResults.js | 49 --------- App/frontend/src/pages/SearchResultsTag.js | 116 +++++++++++++++++++++ 7 files changed, 129 insertions(+), 59 deletions(-) create mode 100644 App/frontend/src/pages/SearchResultsTag.js diff --git a/App/backend/api/views/recommendation.py b/App/backend/api/views/recommendation.py index ec19ee32..9532ed55 100644 --- a/App/backend/api/views/recommendation.py +++ b/App/backend/api/views/recommendation.py @@ -115,6 +115,7 @@ def RecommendArtItemView(request): artitems = [] + # exclude(virtualExhibition__isnull = False) firstcategory = ArtItem.objects.filter(category = category1).exclude(virtualExhibition__isnull = False) for item in firstcategory: histories = History.objects.filter(user=user, is_art=True, art_id=item.id) diff --git a/App/frontend/src/App.js b/App/frontend/src/App.js index f7d0c622..e03ee77a 100644 --- a/App/frontend/src/App.js +++ b/App/frontend/src/App.js @@ -18,7 +18,7 @@ import RecommendedExhibitions from "./pages/RecommendedPages/RecommendedExhibiti import RecommendedUsers from "./pages/RecommendedPages/RecommendedUsers"; import ArtItem from "./pages/ArtItem"; import Settings from "./pages/Settings"; -import SearchResults from "./pages/SearchResults"; +import SearchResultsTag from "./pages/SearchResultsTag"; import Exhibition from "./pages/Exhibition"; function App() { @@ -85,7 +85,7 @@ function App() { element={} > - } /> + } /> ); diff --git a/App/frontend/src/components/Searchbar.js b/App/frontend/src/components/Searchbar.js index 4602d8dd..dc2f620e 100644 --- a/App/frontend/src/components/Searchbar.js +++ b/App/frontend/src/components/Searchbar.js @@ -4,11 +4,11 @@ import Form from "react-bootstrap/Form"; import { AiOutlineSearch } from "react-icons/ai"; import "./styles/Searchbar.css"; -function Searchbar() { - const [input, setInput] = useState(""); +function Searchbar(props) { + const [searchInput, setSearchInput] = useState(""); - function handleInput(e) { - setInput(e.target.value); + function handleSearchInput(e) { + setSearchInput(e.target.value); } return ( @@ -21,8 +21,8 @@ function Searchbar() { placeholder="Search for art items, exhibitions, artists..." className="search-bar" aria-label="Search" - value={input} - onChange={(e) => handleInput(e)} + value={searchInput} + onChange={(e) => handleSearchInput(e)} /> ); diff --git a/App/frontend/src/layout/Layout.js b/App/frontend/src/layout/Layout.js index e8a95596..dd0b12b0 100644 --- a/App/frontend/src/layout/Layout.js +++ b/App/frontend/src/layout/Layout.js @@ -135,6 +135,7 @@ function Layout(props) { mainbarOpen={mainbarOpen} sidebarOpen={sidebarOpen} onClickMenu={() => handleSidebar()} + //setSearchInput={} /> ) : ( handleLogIn()} onClickSignUp={() => handleSignUp()} onClickMenu={() => handleSidebar()} + //setSearchInput={} /> )} diff --git a/App/frontend/src/pages/ArtItem.js b/App/frontend/src/pages/ArtItem.js index f3950531..82445371 100644 --- a/App/frontend/src/pages/ArtItem.js +++ b/App/frontend/src/pages/ArtItem.js @@ -783,7 +783,7 @@ function ArtItem(props) { .catch((error) => console.error("Error:", error)); } - function goToSearchResults(id) { + function goToSearchResultsTag(id) { navigate(`/artitems/tag/${id}`); } @@ -815,7 +815,7 @@ function ArtItem(props) { goToSearchResults(val.id)} + onClick={() => goToSearchResultsTag(val.id)} /> ); })} diff --git a/App/frontend/src/pages/SearchResults.js b/App/frontend/src/pages/SearchResults.js index 0f002394..5408576c 100644 --- a/App/frontend/src/pages/SearchResults.js +++ b/App/frontend/src/pages/SearchResults.js @@ -32,55 +32,6 @@ function SearchResults(props) { const s3 = new AWS.S3(); - useEffect(() => { - fetch(`${host}/api/v1/artitems/tags/?tags=${tag_id}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }) - .then((response) => response.json()) - .then((response) => { - setArtItemInfos(response); - - var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; - var art_item_paths = []; - - for (let i = 0; i < response.length; i++) { - var params = { - Bucket: bucket, - Key: response[i].artitem_path, - }; - - var artitem_url = s3.getSignedUrl("getObject", params); - - art_item_paths.push(artitem_url); - } - - setArtItemPaths(art_item_paths); - }) - .catch((error) => console.error("Error:", error)); - }, [host, tag_id]); - - useEffect(() => { - fetch(`${host}/api/v1/tags/${tag_id}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }) - .then((response) => response.json()) - .then((response) => { - setTagName(response.tagname); - }) - .catch((error) => console.error("Error:", error)); - }, [host, tag_id]); - - function goToArtItem(id) { - navigate(`/artitems/${id}`); - scrollToTop(); - } - return (
diff --git a/App/frontend/src/pages/SearchResultsTag.js b/App/frontend/src/pages/SearchResultsTag.js new file mode 100644 index 00000000..92156778 --- /dev/null +++ b/App/frontend/src/pages/SearchResultsTag.js @@ -0,0 +1,116 @@ +import React, { useState, useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { HOST } from "../constants/host"; +import Layout from "../layout/Layout"; +import * as dotenv from "dotenv"; + +import "./styles/Recommendation.css"; + +function SearchResultsTag(props) { + function scrollToTop() { + window.scrollTo({ + top: 0, + left: 0, + behavior: "instant", + }); + } + + var host = HOST; + const { tag_id } = useParams(); + const navigate = useNavigate(); + + const [artItemInfos, setArtItemInfos] = useState([]); + const [artItemPaths, setArtItemPaths] = useState([]); + const [tagName, setTagName] = useState([]); + + const AWS = require("aws-sdk"); + dotenv.config(); + AWS.config.update({ + accessKeyId: process.env.REACT_APP_AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.REACT_APP_AWS_SECRET_ACCESS_KEY, + }); + + const s3 = new AWS.S3(); + + useEffect(() => { + fetch(`${host}/api/v1/artitems/tags/?tags=${tag_id}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => response.json()) + .then((response) => { + setArtItemInfos(response); + + var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; + var art_item_paths = []; + + for (let i = 0; i < response.length; i++) { + var params = { + Bucket: bucket, + Key: response[i].artitem_path, + }; + + var artitem_url = s3.getSignedUrl("getObject", params); + + art_item_paths.push(artitem_url); + } + + setArtItemPaths(art_item_paths); + }) + .catch((error) => console.error("Error:", error)); + }, [host, tag_id]); + + useEffect(() => { + fetch(`${host}/api/v1/tags/${tag_id}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => response.json()) + .then((response) => { + setTagName(response.tagname); + }) + .catch((error) => console.error("Error:", error)); + }, [host, tag_id]); + + function goToArtItem(id) { + navigate(`/artitems/${id}`); + scrollToTop(); + } + + return ( + +
+
+

Search results for {tagName} tag

+
+ {artItemInfos.map((val, index) => { + return ( +
goToArtItem(val.id)} + > + {val.description} +
+

{val.title}

+

{val.description}

+
+
+ ); + })} +
+
+
+
+ ); +} + +export default SearchResultsTag; From 9071349946d9579a287d0a6f6de89167d503d133 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 05:24:32 +0300 Subject: [PATCH 05/11] initial version of the search is implemented --- App/frontend/src/App.js | 2 + App/frontend/src/components/Searchbar.js | 23 ++- App/frontend/src/pages/SearchResults.js | 186 +++++++++++++++--- .../src/pages/styles/Recommendation.css | 8 + 4 files changed, 195 insertions(+), 24 deletions(-) diff --git a/App/frontend/src/App.js b/App/frontend/src/App.js index e03ee77a..eba0c6b3 100644 --- a/App/frontend/src/App.js +++ b/App/frontend/src/App.js @@ -18,6 +18,7 @@ import RecommendedExhibitions from "./pages/RecommendedPages/RecommendedExhibiti import RecommendedUsers from "./pages/RecommendedPages/RecommendedUsers"; import ArtItem from "./pages/ArtItem"; import Settings from "./pages/Settings"; +import SearchResults from "./pages/SearchResults"; import SearchResultsTag from "./pages/SearchResultsTag"; import Exhibition from "./pages/Exhibition"; @@ -85,6 +86,7 @@ function App() { element={} > + } /> } /> diff --git a/App/frontend/src/components/Searchbar.js b/App/frontend/src/components/Searchbar.js index dc2f620e..50108e4f 100644 --- a/App/frontend/src/components/Searchbar.js +++ b/App/frontend/src/components/Searchbar.js @@ -1,16 +1,35 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; import InputGroup from "react-bootstrap/InputGroup"; import Form from "react-bootstrap/Form"; import { AiOutlineSearch } from "react-icons/ai"; import "./styles/Searchbar.css"; -function Searchbar(props) { +function Searchbar() { + const navigate = useNavigate(); + const [searchInput, setSearchInput] = useState(""); function handleSearchInput(e) { setSearchInput(e.target.value); } + useEffect(() => { + const keyDownHandler = (e) => { + if (e.key === "Enter") { + e.preventDefault(); + + navigate(`/search/${searchInput}`); + } + }; + + document.addEventListener("keydown", keyDownHandler); + + return () => { + document.removeEventListener("keydown", keyDownHandler); + }; + }, [searchInput]); + return ( diff --git a/App/frontend/src/pages/SearchResults.js b/App/frontend/src/pages/SearchResults.js index 5408576c..62d66d3e 100644 --- a/App/frontend/src/pages/SearchResults.js +++ b/App/frontend/src/pages/SearchResults.js @@ -1,5 +1,6 @@ import React, { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; +import { useAuth } from "../auth/authentication"; import { HOST } from "../constants/host"; import Layout from "../layout/Layout"; import * as dotenv from "dotenv"; @@ -16,12 +17,16 @@ function SearchResults(props) { } var host = HOST; - const { tag_id } = useParams(); + const { token } = useAuth(); + const { input } = useParams(); const navigate = useNavigate(); const [artItemInfos, setArtItemInfos] = useState([]); const [artItemPaths, setArtItemPaths] = useState([]); - const [tagName, setTagName] = useState([]); + const [userInfos, setUserInfos] = useState([]); + const [userPaths, setUserPaths] = useState([]); + const [noResult, setNoResult] = useState(false); + const [myID, setMyID] = useState(null); const AWS = require("aws-sdk"); dotenv.config(); @@ -32,31 +37,168 @@ function SearchResults(props) { const s3 = new AWS.S3(); + useEffect(() => { + fetch(`${host}/api/v1/search/lexical/?search=${input}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => response.json()) + .then((response) => { + setArtItemInfos(response); + + var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; + var art_item_paths = []; + + for (let i = 0; i < response.length; i++) { + var params = { + Bucket: bucket, + Key: response[i].artitem_path, + }; + + var artitem_url = s3.getSignedUrl("getObject", params); + + art_item_paths.push(artitem_url); + } + + setArtItemPaths(art_item_paths); + }) + .catch((error) => console.error("Error:", error)); + }, [host, input]); + + useEffect(() => { + fetch(`${host}/api/v1/search/lexical/users/?search=${input}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => response.json()) + .then((response) => { + setUserInfos(response); + + var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; + var user_paths = []; + + for (let i = 0; i < response.length; i++) { + var params = { + Bucket: bucket, + Key: response[i].profile_path, + }; + + var user_url = s3.getSignedUrl("getObject", params); + + user_paths.push(user_url); + } + + setUserPaths(user_paths); + }) + .catch((error) => console.error("Error:", error)); + }, [host, input]); + + useEffect(() => { + var config = {}; + + if (token) { + config = { + "Content-Type": "application/json", + Authorization: `Token ${token}`, + }; + } else { + config = { "Content-Type": "application/json" }; + } + + fetch(`${host}/api/v1/users/profile/me/`, { + method: "GET", + headers: config, + }) + .then((response) => response.json()) + .then((response) => { + setMyID(response.id); + }) + .catch((error) => console.error("Error:", error)); + }, [host]); + + useEffect(() => { + if (artItemInfos.length === 0 && userInfos.length === 0) { + setNoResult(true); + } else { + setNoResult(false); + } + }, [artItemInfos, userInfos]); + + function goToArtItem(id) { + navigate(`/artitems/${id}`); + scrollToTop(); + } + + function goToExhibition(id) { + navigate(`/exhibitions/online/${id}`); + scrollToTop(); + } + + function goToProfile(id) { + if (myID === id) { + navigate(`/my-profile`); + } else { + navigate(`/users/${id}`); + } + + scrollToTop(); + } + return (
-

Search results for {tagName} tag

+

Search results for {input}

- {artItemInfos.map((val, index) => { - return ( -
goToArtItem(val.id)} - > - {val.description} -
-

{val.title}

-

{val.description}

-
-
- ); - })} + {noResult ? ( +
No results found
+ ) : ( + <> + {artItemInfos.map((val, index) => { + return ( +
goToArtItem(val.id)} + > + {val.description} +
+

{val.title}

+

{val.description}

+
+
+ ); + })} + {userInfos.map((val, index) => { + return ( +
goToProfile(val.id)} + > + +
+

{val.username}

+ {/*

{val.name}

+

{val.location}

*/} +
+
+ ); + })} + + )}
diff --git a/App/frontend/src/pages/styles/Recommendation.css b/App/frontend/src/pages/styles/Recommendation.css index dd0488e9..a7779029 100644 --- a/App/frontend/src/pages/styles/Recommendation.css +++ b/App/frontend/src/pages/styles/Recommendation.css @@ -113,9 +113,17 @@ overflow: hidden; text-overflow: ellipsis; } + .recommendation-grid .recommendation-card p { color: #989898; font-size: 12px; line-height: 20px; font-weight: 600; } + +.recommendation-grid .no-results-found { + color: #989898; + font-size: 20px; + font-weight: 300; + margin-top: -1rem; +} From 0fdd6c72d67447aad1a04cb5250514e8f9098224 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 05:26:12 +0300 Subject: [PATCH 06/11] minor addition --- App/frontend/src/pages/SearchResults.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/App/frontend/src/pages/SearchResults.js b/App/frontend/src/pages/SearchResults.js index 62d66d3e..b69c0998 100644 --- a/App/frontend/src/pages/SearchResults.js +++ b/App/frontend/src/pages/SearchResults.js @@ -155,7 +155,7 @@ function SearchResults(props) {

Search results for {input}

{noResult ? ( -
No results found
+
No results found...
) : ( <> {artItemInfos.map((val, index) => { From b5ef55557262a3e5ce99ced20eb5c6b53d2a9fb9 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 05:51:04 +0300 Subject: [PATCH 07/11] change in the sidebar content --- App/frontend/src/layout/data/SidebarData.js | 46 ++++++++++----------- App/frontend/src/pages/Profile.js | 2 +- App/frontend/src/pages/styles/Profile.css | 41 +----------------- 3 files changed, 23 insertions(+), 66 deletions(-) diff --git a/App/frontend/src/layout/data/SidebarData.js b/App/frontend/src/layout/data/SidebarData.js index d3ccca21..8ad371f2 100644 --- a/App/frontend/src/layout/data/SidebarData.js +++ b/App/frontend/src/layout/data/SidebarData.js @@ -1,26 +1,22 @@ export const SidebarData = [ - { - title: "Home", - link: "/" - }, - { - title: "Gallery", - link: "/" - }, - { - title: "Exhibitions", - link: "/" - }, - { - title: "Popular Artists", - link: "/" - }, - { - title: "Discover", - link: "/discover" - }, - { - title: "Add Favourites", - link: "/" - } -] \ No newline at end of file + { + title: "Home", + link: "/", + }, + { + title: "Discover", + link: "/discover", + }, + { + title: "Art Items", + link: "/discover-artitems", + }, + { + title: "Exhibitions", + link: "/discover-exhibitions", + }, + { + title: "Artists", + link: "/discover-users", + }, +]; diff --git a/App/frontend/src/pages/Profile.js b/App/frontend/src/pages/Profile.js index 31b850ee..4c6bdaf0 100644 --- a/App/frontend/src/pages/Profile.js +++ b/App/frontend/src/pages/Profile.js @@ -610,7 +610,7 @@ function Profile(props) { closeUploadArtitemCard={() => setUpload(false)} tags={tags} /> -
PHYSICAL EXHIBITIONS HERE
+ {/*
PHYSICAL EXHIBITIONS HERE
*/} )} diff --git a/App/frontend/src/pages/styles/Profile.css b/App/frontend/src/pages/styles/Profile.css index a7376089..2b408675 100644 --- a/App/frontend/src/pages/styles/Profile.css +++ b/App/frontend/src/pages/styles/Profile.css @@ -35,7 +35,7 @@ -o-border-radius: 50%; border-radius: 50%; object-fit: cover; - box-shadow: 0px 0px 0.9rem #ffffff; + box-shadow: 0px 0px 0.6rem #ffffff; } .profile-username { @@ -253,45 +253,6 @@ background-color: #e0e0e0; } -/*Loader can be used in any related action.*/ - -/*.loader { - width: 5rem; - height: 5rem; - border: 0.6rem solid #999; - border-bottom-color: transparent; - border-radius: 50%; - margin: 0 auto; - animation: loader 500ms linear infinite; -} - -/* Spinner Animation */ -/*@keyframes loader { - to { - transform: rotate(360deg); - } - } -*/ - -/* -The following code will only run if your browser supports CSS grid. -Remove or comment-out the code block below to see how the browser will fall-back to flexbox & floated styling. -*/ - -/*This part makes components in the screen seem better in terms of size when you minimize the size of the screen.*/ - -/*@supports (display: grid) { - .gallery { - grid-gap: 1rem; - } - - .gallery-item, - .gallery { - width: auto; - margin: 0; - } -}*/ - @media (max-width: 1400px) { .profile-container { margin-top: 7rem; From 89c44ca2bbc5ff45952dea57def2887d16c15e52 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 07:36:18 +0300 Subject: [PATCH 08/11] online exhibition search for backend and some styling --- App/backend/api/urls.py | 6 +- App/backend/api/views/search.py | 140 +++++++++++++++++- App/frontend/src/pages/SearchResults.js | 63 +++++++- .../src/pages/styles/Recommendation.css | 47 +++++- 4 files changed, 242 insertions(+), 14 deletions(-) diff --git a/App/backend/api/urls.py b/App/backend/api/urls.py index 4925bd56..6cd8b23e 100644 --- a/App/backend/api/urls.py +++ b/App/backend/api/urls.py @@ -13,7 +13,7 @@ from .views.follow import follow_user, unfollow_user, get_my_followers, get_my_followings, get_followers, get_followings from .views.comments import CommentView, CommentsView from .views.tags import TagView, TagsView -from .views.search import LexSearchView, LexSearchUserView +from .views.search import LexSearchView, LexSearchUserView, search_offline_exhibitions_lexical, search_virtual_exhibitions_lexical from .views.user import users_api from .views.exhibition import get_exhibitions, get_my_exhibitions, create_offline_exhibition, create_online_exhibition, get_online_exhibitions_by_id, get_offline_exhibitions_by_id, get_offline_exhibitions_by_userid, get_online_exhibitions_by_userid from .views.like import like_artitem, unlike_artitem, get_liked_artitems_of_user, get_users_who_liked_artitem, like_comment, unlike_comment, get_users_who_liked_comment @@ -110,7 +110,9 @@ path('artitems/bids//', BidView, name="BidView"), path('artitems/tags/', artitems_by_tags, name="get_artitems_by_tags"), path('search/lexical/', LexSearchView.as_view(), name='LexicalSearch'), - path('search/lexical/users/', LexSearchUserView.as_view(), name='LexicalSearchUser') + path('search/lexical/users/', LexSearchUserView.as_view(), name='LexicalSearchUser'), + path('search/lexical/exhibitions/offline', search_offline_exhibitions_lexical.as_view(), name="search_offline_exhibitions"), + path('search/lexical/exhibitions/online/', search_virtual_exhibitions_lexical.as_view(), name="search_virtual_exhibitions") ] # added to give us the option to choose between default Response template and regular json diff --git a/App/backend/api/views/search.py b/App/backend/api/views/search.py index 04d3e3fb..b056340c 100644 --- a/App/backend/api/views/search.py +++ b/App/backend/api/views/search.py @@ -8,7 +8,10 @@ from ..models.artitem import ArtItem from ..models.user import User +from ..models.exhibition import OfflineExhibition +from ..models.exhibition import VirtualExhibition from ..serializers.serializers import ArtItemSerializer, SimpleUserSerializer +from ..serializers.exhibition import OfflineExhibitionSerializer, VirtualExhibitionSerializer from drf_yasg.utils import swagger_auto_schema from django.contrib.auth.models import AnonymousUser @@ -51,7 +54,7 @@ ) class LexSearchView(ListAPIView): - queryset = ArtItem.objects.all() + queryset = ArtItem.objects.all().exclude(virtualExhibition__isnull = False) serializer_class = ArtItemSerializer filter_backends = (SearchFilter, OrderingFilter) search_fields = ('title', 'description', 'owner__name', 'owner__surname', 'tags__tagname') @@ -87,4 +90,137 @@ class LexSearchUserView(ListAPIView): queryset = User.objects.all() serializer_class = SimpleUserSerializer filter_backends = (SearchFilter, OrderingFilter) - search_fields = ('username', 'name', 'surname') \ No newline at end of file + search_fields = ('username', 'name', 'surname') + + +@swagger_auto_schema( + # method='get', + operation_description= "Searchs for offline exhibitions by their titles and descriptions.", + operation_summary="Get all the offline exhibitions according to their titles and descriptions.", + tags=['search'], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Successfully retrieved all the offline exhibitions according to the search params.", + examples={ + "application/json": [ + { + "owner": + [ + { + "id": 1, + "owner": { + "id": 1, + "username": "denemes", + "name": "", + "surname": "", + "profile_path": "avatar/default.png" + }, + "title": "My Offline Exhibition", + "description": "Art exhibition at street 123.", + "poster": { + "id": 1, + "owner": 1, + "title": "My Offline Exhibition", + "description": "Art exhibition at street 123.", + "category": "PT", + "tags": [], + "artitem_path": "artitem/artitem-1.png", + "created_at": "08-12-2022 23:31:44" + }, + "collaborators": [], + "start_date": "08-12-2022 16:00:00", + "end_date": "10-12-2020 16:00:00", + "created_at": "08-12-2022 23:31:44", + "updated_at": "08-12-2022 23:31:44", + "city": "İstanbul", + "country": "Türkiye", + "address": "Beyoglu", + "latitude": 41.40338, + "longitude": 28.97835, + "status": "Ongoing" + } + ], + "collaborator": [] + } + ] + } + ) + } + +) + +class search_offline_exhibitions_lexical(ListAPIView): + queryset = OfflineExhibition.objects.all() + serializer_class = OfflineExhibitionSerializer + filter_backends = (SearchFilter, OrderingFilter) + search_fields = ('title', 'description') + + +@swagger_auto_schema( + # method='get', + operation_description= "Searchs for virtual exhibitions by their titles and descriptions.", + operation_summary="Get all the virtual exhibitions according to their titles and descriptions.", + tags=['search'], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Successfully retrieved all the virtual exhibitions according to the search params.", + examples={ + "application/json": [ + { + "owner": + [ + { + "id": 1, + "owner": { + "id": 1, + "username": "denemes", + "name": "", + "surname": "", + "profile_path": "avatar/default.png" + }, + "title": "My Offline Exhibition", + "description": "Art exhibition at street 123.", + "poster": { + "id": 4, + "owner": 1, + "title": "My Offline Exhibition", + "description": "Art exhibition at street 123.", + "category": "PT", + "tags": [], + "artitem_path": "artitem/artitem-4.png", + "created_at": "08-12-2022 23:32:34" + }, + "collaborators": [], + "artitems_gallery": [ + { + "id": 3, + "owner": 1, + "title": "Portrait of Joel Miller", + "description": "Joel Miller from TLOU universe.", + "category": "OT", + "tags": [], + "artitem_path": "artitem/artitem-3.png", + "created_at": "08-12-2022 23:32:18" + } + ], + "start_date": "08-12-2022 16:00:00", + "end_date": "10-12-2020 16:00:00", + "created_at": "08-12-2022 23:32:34", + "updated_at": "08-12-2022 23:32:34", + "status": "Ongoing" + } + ], + "collaborator": [] + } + ] + } + ) + } + +) + +class search_virtual_exhibitions_lexical(ListAPIView): + queryset = VirtualExhibition.objects.all() + serializer_class = VirtualExhibitionSerializer + filter_backends = (SearchFilter, OrderingFilter) + search_fields = ('title', 'description') \ No newline at end of file diff --git a/App/frontend/src/pages/SearchResults.js b/App/frontend/src/pages/SearchResults.js index b69c0998..fcdf8c9c 100644 --- a/App/frontend/src/pages/SearchResults.js +++ b/App/frontend/src/pages/SearchResults.js @@ -23,6 +23,8 @@ function SearchResults(props) { const [artItemInfos, setArtItemInfos] = useState([]); const [artItemPaths, setArtItemPaths] = useState([]); + const [exhibitionInfos, setExhibitionInfos] = useState([]); + const [exhibitionPaths, setExhibitionPaths] = useState([]); const [userInfos, setUserInfos] = useState([]); const [userPaths, setUserPaths] = useState([]); const [noResult, setNoResult] = useState(false); @@ -67,6 +69,36 @@ function SearchResults(props) { .catch((error) => console.error("Error:", error)); }, [host, input]); + useEffect(() => { + fetch(`${host}/api/v1/search/lexical/exhibitions/online/?search=${input}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => response.json()) + .then((response) => { + setExhibitionInfos(response); + + var bucket = process.env.REACT_APP_AWS_STORAGE_BUCKET_NAME; + var poster_paths = []; + + for (let i = 0; i < response.length; i++) { + var params = { + Bucket: bucket, + Key: response[i].poster.artitem_path, + }; + + var poster_url = s3.getSignedUrl("getObject", params); + + poster_paths.push(poster_url); + } + + setExhibitionPaths(poster_paths); + }) + .catch((error) => console.error("Error:", error)); + }, [host, input]); + useEffect(() => { fetch(`${host}/api/v1/search/lexical/users/?search=${input}`, { method: "GET", @@ -121,12 +153,16 @@ function SearchResults(props) { }, [host]); useEffect(() => { - if (artItemInfos.length === 0 && userInfos.length === 0) { + if ( + artItemInfos.length === 0 && + exhibitionInfos.length === 0 && + userInfos.length === 0 + ) { setNoResult(true); } else { setNoResult(false); } - }, [artItemInfos, userInfos]); + }, [artItemInfos, exhibitionInfos, userInfos]); function goToArtItem(id) { navigate(`/artitems/${id}`); @@ -177,11 +213,30 @@ function SearchResults(props) {
); })} + {exhibitionInfos.map((val, index) => { + return ( +
goToExhibition(val.id)} + > + {val.description} +
+

{val.title}

+

{val.description}

+
+
+ ); + })} {userInfos.map((val, index) => { return (
goToProfile(val.id)} >
-

{val.username}

+

{val.username}

{/*

{val.name}

{val.location}

*/}
diff --git a/App/frontend/src/pages/styles/Recommendation.css b/App/frontend/src/pages/styles/Recommendation.css index a7779029..c6611534 100644 --- a/App/frontend/src/pages/styles/Recommendation.css +++ b/App/frontend/src/pages/styles/Recommendation.css @@ -60,6 +60,32 @@ transition: all ease 0.4s; } +.recommendation-grid .art-gallery .recommendation-card-exhibition { + margin-bottom: 1.25rem; + -webkit-column-break-inside: avoid; + page-break-inside: avoid; + break-inside: avoid; + height: auto; + padding: 1rem; + background-color: #7a7081; + border-radius: 6px; + cursor: pointer; + transition: all ease 0.4s; +} + +.recommendation-grid .art-gallery .recommendation-card-user { + margin-bottom: 1.25rem; + -webkit-column-break-inside: avoid; + page-break-inside: avoid; + break-inside: avoid; + height: auto; + padding: 1rem; + background-color: #bab0c1; + border-radius: 6px; + cursor: pointer; + transition: all ease 0.4s; +} + .recommendation-grid .list .recommendation-card { height: auto; padding: 1rem; @@ -68,18 +94,27 @@ cursor: pointer; transition: all ease 0.4s; } + .recommendation-grid .recommendation-card:hover { background-color: #4a3c4a; } -.recommendation-grid .recommendation-card .art-related { +.recommendation-grid .recommendation-card-exhibition:hover { + background-color: #9a8c9a; +} + +.recommendation-grid .recommendation-card-user:hover { + background-color: #978997; +} + +.recommendation-grid .art-related { width: 100%; height: auto; border-radius: 6px; margin-bottom: 10px; } -.recommendation-grid .recommendation-card .profile-photo { +.recommendation-grid .profile-photo { display: block; margin-left: auto; margin-right: auto; @@ -91,13 +126,13 @@ object-fit: cover; } -.recommendation-grid .recommendation-card .artitem-context { +.recommendation-grid .artitem-context { position: relative; max-width: 200px; overflow: hidden; } -.recommendation-grid .recommendation-card .profile-context { +.recommendation-grid .profile-context { position: relative; text-align: center; margin-top: 1.25rem; @@ -105,7 +140,7 @@ overflow: hidden; } -.recommendation-grid .recommendation-card h4 { +.recommendation-grid h4 { color: #ffffff; font-size: 14px; margin-bottom: 10px; @@ -114,7 +149,7 @@ text-overflow: ellipsis; } -.recommendation-grid .recommendation-card p { +.recommendation-grid p { color: #989898; font-size: 12px; line-height: 20px; From 666ca390ae09b6d8b081402aee9217d2b98c3105 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 07:41:23 +0300 Subject: [PATCH 09/11] minor change in css --- App/frontend/src/pages/SearchResults.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/App/frontend/src/pages/SearchResults.js b/App/frontend/src/pages/SearchResults.js index fcdf8c9c..25e0d03a 100644 --- a/App/frontend/src/pages/SearchResults.js +++ b/App/frontend/src/pages/SearchResults.js @@ -236,7 +236,7 @@ function SearchResults(props) { return (
goToProfile(val.id)} >
-

{val.username}

+

{val.username}

{/*

{val.name}

{val.location}

*/}
From 482461d7ad2c1456672062984a52ad69e946d3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karahan=20Sar=C4=B1ta=C5=9F?= <44376034+KarahanS@users.noreply.github.com> Date: Tue, 27 Dec 2022 09:25:42 +0300 Subject: [PATCH 10/11] fix: Correct offline exhibition URL --- App/backend/api/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/App/backend/api/urls.py b/App/backend/api/urls.py index 6cd8b23e..fd4326a7 100644 --- a/App/backend/api/urls.py +++ b/App/backend/api/urls.py @@ -111,7 +111,7 @@ path('artitems/tags/', artitems_by_tags, name="get_artitems_by_tags"), path('search/lexical/', LexSearchView.as_view(), name='LexicalSearch'), path('search/lexical/users/', LexSearchUserView.as_view(), name='LexicalSearchUser'), - path('search/lexical/exhibitions/offline', search_offline_exhibitions_lexical.as_view(), name="search_offline_exhibitions"), + path('search/lexical/exhibitions/offline/', search_offline_exhibitions_lexical.as_view(), name="search_offline_exhibitions"), path('search/lexical/exhibitions/online/', search_virtual_exhibitions_lexical.as_view(), name="search_virtual_exhibitions") ] From 2391aa9a9f14ec3de7edc6f7c77d3a644eddba03 Mon Sep 17 00:00:00 2001 From: Furkan Keskin Date: Tue, 27 Dec 2022 11:56:36 +0300 Subject: [PATCH 11/11] emptied home gallery --- App/frontend/src/components/HomeGalleryCard.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/App/frontend/src/components/HomeGalleryCard.js b/App/frontend/src/components/HomeGalleryCard.js index ec0f947e..c74fcc21 100644 --- a/App/frontend/src/components/HomeGalleryCard.js +++ b/App/frontend/src/components/HomeGalleryCard.js @@ -28,7 +28,11 @@ function HomeGalleryCard(props) {
Featured Art Items
goToArtItem(1)} + onClick={ + { + /*() => goToArtItem(1)*/ + } + } source={lost} name="Lost Highway" />