From 16cee03332aa556718a46718f94cd8413b055925 Mon Sep 17 00:00:00 2001 From: LogJurgenR Date: Wed, 19 Aug 2026 17:15:28 +0200 Subject: [PATCH] Zoek functie voor items toegevoegd --- app/items-results.tsx | 104 ++++++++++++++++++++++++++++++++++++++++++ app/page.tsx | 81 +------------------------------- app/search.tsx | 42 +++++++++++++++++ lib/i18n.ts | 4 ++ lib/items.ts | 23 +++++++++- 5 files changed, 174 insertions(+), 80 deletions(-) create mode 100644 app/items-results.tsx create mode 100644 app/search.tsx diff --git a/app/items-results.tsx b/app/items-results.tsx new file mode 100644 index 0000000..def272b --- /dev/null +++ b/app/items-results.tsx @@ -0,0 +1,104 @@ +"use client"; + +import SearchButton from "@/app/search"; +import { t, type Locale } from "@/lib/i18n"; +import type { Item } from "@/lib/items"; +import { useState } from "react"; + +export default function ItemsResults({ + initialItems, + initialError, + locale, +}: { + initialItems: Item[]; + initialError: string; + locale: Locale; +}) { + const [items, setItems] = useState(initialItems); + const [error, setError] = useState(initialError); + + function handleResults(nextItems: Item[], nextError: string) { + setItems(nextItems); + setError(nextError); + } + + return ( + <> +
+
+
+

{t(locale, "articles.count")}

+

{items.length}

+
+
+
+ +
+
+

+ {t(locale, "articles.heading")} +

+
+ + +
+
+ + {error && ( +
+ {t(locale, "articles.error")} +
+ )} + + {items.length > 0 && ( +
+ + + + + + + + + {items.map((item) => ( + + + + + ))} + +
+ {t(locale, "articles.code")} + + {t(locale, "articles.descriptionColumn")} +
+ {item.ItemCode} + {item.ItemName}
+
+ )} + + {items.length === 0 && !error && ( +
+
+ πŸ“¦ +
+

+ {t(locale, "articles.emptyTitle")} +

+

+ {t(locale, "articles.emptyDescription")} +

+
+ )} +
+ + ); +} \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 0fab664..bebe448 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,6 @@ import LogoutButton from "@/app/logout-button"; import LanguageSwitcher from "@/app/language-switcher"; +import ItemsResults from "@/app/items-results"; import { getItems } from "@/lib/items"; import { cookies } from "next/headers"; import { getLocale, LOCALE_COOKIE, t } from "@/lib/i18n"; @@ -31,85 +32,7 @@ export default async function ItemsPage() {
- {/* KPI Card */} -
-
-
-

{t(locale, "articles.count")}

-

- {items.length} -

-
-
-
- - {/* Main Card */} -
-
-

- {t(locale, "articles.heading")} -

-
- - {/* Error */} - {error && ( -
- {t(locale, "articles.error")} -
- )} - - {/* Table */} - {items.length > 0 && ( -
- - - - - - - - - - {items.map((item) => ( - - - - - - ))} - -
- {t(locale, "articles.code")} - - {t(locale, "articles.descriptionColumn")} -
- {item.ItemCode} - - {item.ItemName} -
-
- )} - - {/* Empty State */} - {items.length === 0 && !error && ( -
-
- πŸ“¦ -
- -

- {t(locale, "articles.emptyTitle")} -

- -

- {t(locale, "articles.emptyDescription")} -

-
- )} -
+
); diff --git a/app/search.tsx b/app/search.tsx new file mode 100644 index 0000000..286c604 --- /dev/null +++ b/app/search.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { useState } from "react"; +import { t, type Locale } from "@/lib/i18n"; +import { searchItems, type Item } from "@/lib/items"; + +export default function SearchButton({ + locale, + onResults, +}: { + locale: Locale; + onResults: (items: Item[], error: string) => void; +}) { + const [loading, setLoading] = useState(false); + + async function handleSearch() { + const query = (document.getElementById("search-input") as HTMLInputElement)?.value.trim(); + if (!query) return; + + setLoading(true); + + try { + const result = await searchItems(query); + onResults(result.items, result.error); + } finally { + setLoading(false); + } + } + + return ( + <> + + + + ); +} \ No newline at end of file diff --git a/lib/i18n.ts b/lib/i18n.ts index 5082df0..31e6798 100644 --- a/lib/i18n.ts +++ b/lib/i18n.ts @@ -15,6 +15,7 @@ type TranslationKey = | "articles.emptyTitle" | "articles.emptyDescription" | "articles.error" + | "articles.search" | "auth.logout" | "login.title" | "login.description" @@ -40,6 +41,7 @@ const translations: Record> = { "articles.emptyTitle": "Geen artikelen gevonden", "articles.emptyDescription": "De Service Layer heeft geen artikelen teruggegeven.", "articles.error": "Er is een fout opgetreden bij het ophalen van de artikelen.", + "articles.search": "Zoeken", "auth.logout": "Uitloggen", "login.title": "Inloggen", "login.description": "Log in om de artikelen te bekijken.", @@ -64,6 +66,7 @@ const translations: Record> = { "articles.emptyTitle": "No items found", "articles.emptyDescription": "The Service Layer returned no items.", "articles.error": "An error occurred while retrieving the items.", + "articles.search": "Search", "auth.logout": "Log out", "login.title": "Sign in", "login.description": "Sign in to view the items.", @@ -88,6 +91,7 @@ const translations: Record> = { "articles.emptyTitle": "ζ΅ε””εˆ°θ²¨ε“", "articles.emptyDescription": "Service Layer ε†‡θΏ”ε›žδ»»δ½•θ²¨ε“γ€‚", "articles.error": "ε–εΎ—θ²¨ε“ζ™‚η™Όη”ŸιŒ―θͺ€γ€‚", + "articles.search": "ζœε°‹", "auth.logout": "η™»ε‡Ί", "login.title": "η™»ε…₯", "login.description": "η™»ε…₯後ζŸ₯ηœ‹θ²¨ε“γ€‚", diff --git a/lib/items.ts b/lib/items.ts index e5291cf..46f3018 100644 --- a/lib/items.ts +++ b/lib/items.ts @@ -1,7 +1,9 @@ +"use server"; + import { executeHttpRequest } from "@sap-cloud-sdk/http-client"; -type Item = { +export type Item = { ItemCode: string; ItemName: string; }; @@ -22,3 +24,22 @@ export async function getItems(): Promise<{ items: Item[]; error: string }> { }; } } + +export async function searchItems(query: string): Promise<{ items: Item[]; error: string }> { + const escapedQuery = query.replaceAll("'", "''"); + + try { + const response = await executeHttpRequest( + { destinationName: "SAP4SL" }, + { method: "GET", url: `/b1s/v2/Items?$filter=contains(ItemName,'${escapedQuery}')` }, + ); + + return { items: response.data.value || [], error: "" }; + } catch (error) { + console.error(error); + return { + items: [], + error: "items_request_failed", + }; + } +}