From 21d2cb158eb96e74b72c9e080444cbe6b47a8791 Mon Sep 17 00:00:00 2001 From: DevOFVictory <49123418+mafeth@users.noreply.github.com> Date: Wed, 8 Oct 2025 17:26:35 +0200 Subject: [PATCH] update --- apis/searchApi.ts | 29 +++++ app/(tabs)/explore.tsx | 220 +++++++++++++++++++++++----------- app/tabStyles/indexStyles.tsx | 63 +++++++--- 3 files changed, 222 insertions(+), 90 deletions(-) create mode 100644 apis/searchApi.ts diff --git a/apis/searchApi.ts b/apis/searchApi.ts new file mode 100644 index 0000000..6602dbc --- /dev/null +++ b/apis/searchApi.ts @@ -0,0 +1,29 @@ +export type SearchItemType = "SHOW" | "PERSON" | "SEASON" | string; + +export type SearchResultItem = { + type: SearchItemType; + data: any; +}; + +const DISCOVER_BASE = "http://45.157.177.99:8080/discover/search"; + +export async function getSearchResults( + tags: string[] | string, + limit = 10, + signal?: AbortSignal +): Promise { + const tagList = Array.isArray(tags) ? tags : [tags]; + const filteredTags = tagList.map((t) => t.trim()).filter(Boolean); + if (!filteredTags.length) return []; + + const url = `${DISCOVER_BASE}?tags=${encodeURIComponent( + filteredTags.join(",") + )}&limit=${limit}`; + + const res = await fetch(url, { signal }); + if (!res.ok) throw new Error("AutoComplete failed " + res.status); + + const data: unknown = await res.json(); + if (!Array.isArray(data)) return []; + return data as SearchResultItem[]; +} diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx index 6a6e593..6989eac 100644 --- a/app/(tabs)/explore.tsx +++ b/app/(tabs)/explore.tsx @@ -1,41 +1,70 @@ +import { AutoCompleteItem } from "@/apis/autoCompleteApi"; +import { getSearchResults, SearchResultItem } from "@/apis/searchApi"; import styles from "@/app/tabStyles/indexStyles"; +import { useDiscoveryContext } from "@/contexts/DiscoveryContext"; +import { FontAwesome } from "@expo/vector-icons"; +import Feather from "@expo/vector-icons/Feather"; import React from "react"; import { - Text, - View, - TextInput, - FlatList, - TouchableOpacity, Keyboard, - TouchableWithoutFeedback, + ScrollView, + Text, + TextInput, + TouchableOpacity, + View } from "react-native"; -import Feather from "@expo/vector-icons/Feather"; -import { useDiscoveryContext } from "@/contexts/DiscoveryContext"; -import { useShowContext } from "@/contexts/ShowContext"; + export default function TabTwoScreen() { - const { query, setQuery, suggestions, loading, error, clear } = - useDiscoveryContext(); + const { query, setQuery, suggestions } = useDiscoveryContext(); - const { shows } = useShowContext(); + const [tags, setTags] = React.useState([]); + + const [searchResults, setSearchResults] = React.useState([]); + + const getIconName = (type: AutoCompleteItem["type"]) => { + switch (type) { + case "PERSON": + return "user"; + case "SHOW": + return "television"; + case "YEAR": + return "calendar"; + default: + return "tag"; + } + }; + + function tagAdded(tag: AutoCompleteItem) { + console.log("Tag added:", tag); + const nextTags = tags.some((t) => t.text === tag.text) + ? tags + : [...tags, tag]; + + setTags(nextTags); + + const tagStrings = nextTags.map((t) => t.text); + + getSearchResults(tagStrings, 20) + .then(setSearchResults) + .catch(console.error); + + setQuery(""); + Keyboard.dismiss(); + + console.log("Searching with tags:", tagStrings); + } - const personSuggestions = React.useMemo( - () => suggestions.filter((s) => s.type === "PERSON"), - [suggestions] - ); - const showSuggestions = React.useMemo( - () => suggestions.filter((s) => s.type === "SHOW"), - [suggestions] - ); - const [tag, setTag] = React.useState(null); return ( - - - - Durchsuchen - + + + Durchsuchen + + + + { - console.log("Search:", query); - }} + onSubmitEditing={() => console.log("Search:", query)} autoCapitalize="none" /> @@ -67,52 +96,101 @@ export default function TabTwoScreen() { )} - {tag && ( - - {tag} - setTag(null)} - style={{ marginLeft: "auto", marginRight: 10 }} - /> - - )} + + {tags.map((tag) => ( + + setTags((prev) => prev.filter((t) => t.text !== tag.text)) + } + > + + + {tag.text} + + + + ))} + {query.length > 0 && ( - <> - - Suchvorschläge + + Suchvorschläge + + {suggestions.map((suggestion, idx) => ( + { + tagAdded(suggestion); + }} + > + + {suggestion.text} + + ))} - {showSuggestions.map((suggestion, idx) => ( - { - setTag(suggestion.text); - }} - > - - {suggestion.text} - - ))} - {personSuggestions.map((suggestion, idx) => ( - { - setTag(suggestion.text); - }} - > - - {suggestion.text} - - ))} - - + + + + )} - + + + + + {searchResults.map((result: SearchResultItem, idx) => { + switch (result.type) { + case "PERSON": + return ( + + + + + + {/* Text */} + + {result.data.name || "Unbekannt"} ({"25"}) + + aus: {"unterscheidlichen Shows"} + + + + {/* Chevron */} + + + ); + case "SHOW": + return ( + + + {result.data.title} (Show) + + + ); + default: + return null; + } + })} + + + + + ); } diff --git a/app/tabStyles/indexStyles.tsx b/app/tabStyles/indexStyles.tsx index 94752da..95fbe68 100644 --- a/app/tabStyles/indexStyles.tsx +++ b/app/tabStyles/indexStyles.tsx @@ -4,6 +4,7 @@ export default StyleSheet.create({ mainContainer: { flex: 1, backgroundColor: "hsl(221, 39%, 11%)", + // paddingHorizontal: 10, }, header: { height: 125, @@ -43,7 +44,7 @@ export default StyleSheet.create({ marginTop: 20, }, searchContainer: { - width: "90%", + width: "100%", height: 60, marginHorizontal: "auto", backgroundColor: "hsl(221, 39%, 8%)", @@ -71,7 +72,10 @@ export default StyleSheet.create({ fontWeight: "500", }, suggestionsSection: { - width: "90%", + position: "absolute", + zIndex: 10, + top: 70, + width: "100%", height: "auto", paddingBottom: 15, borderRadius: 20, @@ -89,6 +93,7 @@ export default StyleSheet.create({ shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 5, + // opacity: 0.9, }, suggestionTitle: { color: "hsl(0, 0%, 60%)", @@ -119,26 +124,46 @@ export default StyleSheet.create({ fontWeight: "500", marginLeft: 10, }, - tagContainer: { + tag: { flexDirection: "row", alignItems: "center", - backgroundColor: "hsl(221, 39%, 8%)", - borderWidth: 1.5, - borderColor: "hsl(221, 39%, 15%)", - height: "auto", - width: "auto", - paddingVertical: 10, - borderRadius: 50, - marginTop: 15, - marginLeft: 20, - - justifyContent: "space-between", + backgroundColor: "#333", + borderRadius: 999, + paddingHorizontal: 10, + paddingVertical: 6, + marginRight: 8, + marginBottom: 8, + marginTop: 5, }, tagLabel: { - color: "hsl(0, 0%, 90%)", - fontSize: 14, - fontWeight: "500", - marginLeft: 15, - textAlign: "center", + color: "white", + marginRight: 5 }, + tagContainer: { + width: "100%", + flexDirection: "row", + flexWrap: "wrap", + marginTop: 10, + }, + personRow: { + width: "100%", + flexDirection: "row", + alignItems: "center", + backgroundColor: "#1b1e2b", + borderRadius: 10, + paddingHorizontal: 10, + paddingVertical: 10, + marginBottom: 8, + }, + avatarCircle: { + width: 40, + height: 40, + borderRadius: 999, + backgroundColor: "#2a2f45", + alignItems: "center", + justifyContent: "center", + marginRight: 10, + }, + personName: { color: "white", fontSize: 16, fontWeight: "600" }, + personMeta: { color: "#bbb", fontSize: 12, marginTop: 2 }, });