From 76a797e01f5784760fc25ba35555d32a410441d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:02:53 +0000 Subject: [PATCH 1/7] Bump react-i18next from 15.0.2 to 16.0.0 Bumps [react-i18next](https://github.com/i18next/react-i18next) from 15.0.2 to 16.0.0. - [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/react-i18next/compare/v15.0.2...v16.0.0) --- updated-dependencies: - dependency-name: react-i18next dependency-version: 16.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 41 +++++++++++++++++++---------------------- package.json | 2 +- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 16dc1cd51..f62aaca19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "react-dom": "^18.1.0", "react-error-boundary": "^6.0.0", "react-gtm-module": "^2.0.11", - "react-i18next": "^15.0.1", + "react-i18next": "^16.0.0", "react-image-crop": "^11.0.6", "react-range-slider-input": "^3.2.1", "react-router": "^7.5.2", @@ -1868,22 +1868,14 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", - "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime/node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/@babel/template": { "version": "7.26.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", @@ -8605,9 +8597,9 @@ } }, "node_modules/i18next": { - "version": "25.0.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.0.2.tgz", - "integrity": "sha512-xWxgK8GAaPYkV9ia2tdgbtdM+qiC+ysVTBPvXhpCORU/+QkeQe3BSI7Crr+c4ZXULN1PfnXG/HY2n7HGx4KKBg==", + "version": "25.5.3", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.3.tgz", + "integrity": "sha512-joFqorDeQ6YpIXni944upwnuHBf5IoPMuqAchGVeQLdWC2JOjxgM9V8UGLhNIIH/Q8QleRxIi0BSRQehSrDLcg==", "funding": [ { "type": "individual", @@ -8624,7 +8616,7 @@ ], "license": "MIT", "dependencies": { - "@babel/runtime": "^7.26.10" + "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" @@ -11139,16 +11131,18 @@ "integrity": "sha512-8gyj4TTxeP7eEyc2QKawEuQoAZdjKvMY4pgWfycGmqGByhs17fR+zEBs0JUDq4US/l+vbTl+6zvUIx27iDo/Vw==" }, "node_modules/react-i18next": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz", - "integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.0.0.tgz", + "integrity": "sha512-JQ+dFfLnFSKJQt7W01lJHWRC0SX7eDPobI+MSTJ3/gP39xH2g33AuTE7iddAfXYHamJdAeMGM0VFboPaD3G68Q==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.25.0", + "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { - "i18next": ">= 23.2.3", - "react": ">= 16.8.0" + "i18next": ">= 25.5.2", + "react": ">= 16.8.0", + "typescript": "^5" }, "peerDependenciesMeta": { "react-dom": { @@ -11156,6 +11150,9 @@ }, "react-native": { "optional": true + }, + "typescript": { + "optional": true } } }, diff --git a/package.json b/package.json index 44fbe8b7a..dc03e0e0f 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "react-dom": "^18.1.0", "react-error-boundary": "^6.0.0", "react-gtm-module": "^2.0.11", - "react-i18next": "^15.0.1", + "react-i18next": "^16.0.0", "react-image-crop": "^11.0.6", "react-range-slider-input": "^3.2.1", "react-router": "^7.5.2", From 58279dc26060686a2301db82aa1e0a58b3c3eb30 Mon Sep 17 00:00:00 2001 From: RobinMeles Date: Fri, 3 Oct 2025 10:18:30 +0200 Subject: [PATCH 2/7] change expire_at in sample files for vouchers and productvouchers --- .../components/modals/ModalVouchersUpload.tsx | 2 +- react/src/dashboard/services/VoucherService.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/react/src/dashboard/components/modals/ModalVouchersUpload.tsx b/react/src/dashboard/components/modals/ModalVouchersUpload.tsx index 79b423398..a36112490 100644 --- a/react/src/dashboard/components/modals/ModalVouchersUpload.tsx +++ b/react/src/dashboard/components/modals/ModalVouchersUpload.tsx @@ -48,7 +48,7 @@ type CSVErrorProp = { type RowDataProp = { _uid?: string; amount?: number; - expires_at?: string; + expire_at?: string; note?: string; bsn?: string; email?: string; diff --git a/react/src/dashboard/services/VoucherService.ts b/react/src/dashboard/services/VoucherService.ts index 6d66b6416..18afcdcec 100644 --- a/react/src/dashboard/services/VoucherService.ts +++ b/react/src/dashboard/services/VoucherService.ts @@ -128,16 +128,16 @@ export class VoucherService { return this.apiRequest.post(`${this.prefix}/${organizationId}/sponsor/transactions`, data); } - public sampleCSVBudgetVoucher(expires_at = '2020-02-20'): string { - const headers = ['amount', 'expires_at', 'note', 'email', 'activate', 'activation_code', 'client_uid']; - const values = [10, expires_at, 'voorbeeld notitie', 'test@example.com', 0, 0, '']; + public sampleCSVBudgetVoucher(expire_at = '2020-02-20'): string { + const headers = ['amount', 'expire_at', 'note', 'email', 'activate', 'activation_code', 'client_uid']; + const values = [10, expire_at, 'voorbeeld notitie', 'test@example.com', 0, 0, '']; return Papa.unparse([headers, values]); } - public sampleCSVProductVoucher(product_id = null, expires_at = '2020-02-20'): string { - const headers = ['product_id', 'expires_at', 'note', 'email', 'activate', 'activation_code', 'client_uid']; - const values = [product_id, expires_at, 'voorbeeld notitie', 'test@example.com', 0, 0, '']; + public sampleCSVProductVoucher(product_id = null, expire_at = '2020-02-20'): string { + const headers = ['product_id', 'expire_at', 'note', 'email', 'activate', 'activation_code', 'client_uid']; + const values = [product_id, expire_at, 'voorbeeld notitie', 'test@example.com', 0, 0, '']; return Papa.unparse([headers, values]); } From daae2bea16990b2ab88e239fb2b9d4dd25dfbc0f Mon Sep 17 00:00:00 2001 From: Yaroslav Kosterin Date: Wed, 8 Oct 2025 16:02:06 +0300 Subject: [PATCH 3/7] fix faq mobile styles --- react/assets/forus-webshop/scss/includes/blocks/block-faq.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss b/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss index 1310e94db..0d516661f 100644 --- a/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss +++ b/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss @@ -119,6 +119,7 @@ gap: 20px; .block-faq-header { + width: 100%; margin-bottom: 5px; .block-faq-title { @@ -131,6 +132,8 @@ } .faq-item { + width: 100%; + .faq-item-header { padding: 15px 14px 15px 15px; From 71108aa0f05bc5065cd69de25e0f4c423b776231 Mon Sep 17 00:00:00 2001 From: dev-rminds Date: Wed, 8 Oct 2025 17:35:07 +0300 Subject: [PATCH 4/7] fix incorrect word placement in search results for some translations --- react/src/webshop/components/pages/search/Search.tsx | 3 +-- react/src/webshop/i18n/nl/pages/search.mjs | 2 +- react/src/webshop/i18n/translated/ar.json | 4 ++-- react/src/webshop/i18n/translated/de.json | 4 ++-- react/src/webshop/i18n/translated/en-US.json | 2 +- react/src/webshop/i18n/translated/fr.json | 4 ++-- react/src/webshop/i18n/translated/pl.json | 4 ++-- react/src/webshop/i18n/translated/ru.json | 4 ++-- react/src/webshop/i18n/translated/tr.json | 4 ++-- react/src/webshop/i18n/translated/uk.json | 4 ++-- translations/cache/cache.json | 2 +- 11 files changed, 18 insertions(+), 19 deletions(-) diff --git a/react/src/webshop/components/pages/search/Search.tsx b/react/src/webshop/components/pages/search/Search.tsx index 9d77a2cf9..1f346a280 100644 --- a/react/src/webshop/components/pages/search/Search.tsx +++ b/react/src/webshop/components/pages/search/Search.tsx @@ -358,10 +358,9 @@ export default function Search() {
- {translate('search.title')} {filterValuesActive.q && ( - {' ' + translate('search.filters.found_for', { query: filterValuesActive.q })} + {translate('search.filters.found_for', { query: filterValuesActive.q })} )}
diff --git a/react/src/webshop/i18n/nl/pages/search.mjs b/react/src/webshop/i18n/nl/pages/search.mjs index 72807ac79..f479e96cb 100644 --- a/react/src/webshop/i18n/nl/pages/search.mjs +++ b/react/src/webshop/i18n/nl/pages/search.mjs @@ -9,7 +9,7 @@ export default { category: 'Categorie', funds: 'Tegoeden', providers: 'Aanbieders', - found_for: 'gevonden voor "{{ query }}"', + found_for: 'Zoekresultaten gevonden voor "{{ query }}"', sort: 'Sorteer', all_funds: 'Selecteer tegoeden...', all_providers: 'Selecteer aanbieder...', diff --git a/react/src/webshop/i18n/translated/ar.json b/react/src/webshop/i18n/translated/ar.json index d8da5eafc..329f0328f 100644 --- a/react/src/webshop/i18n/translated/ar.json +++ b/react/src/webshop/i18n/translated/ar.json @@ -1669,11 +1669,11 @@ "all_providers": "حدد المزود...", "all_sub_categories": "اختر الفئة الفرعية...", "category": "الفئة", - "found_for": "{{ query }}وجدت لـ \"\"", "funds": "الائتمان", "highlighted": "مميز", "providers": "المزودون", - "sort": "فرز" + "sort": "فرز", + "found_for": "تم العثور على نتائج البحث عن \"{{ query }}\"" }, "sort_by": { "created_at_asc": "الأقدم أولاً", diff --git a/react/src/webshop/i18n/translated/de.json b/react/src/webshop/i18n/translated/de.json index 5c402e815..b7aa445ac 100644 --- a/react/src/webshop/i18n/translated/de.json +++ b/react/src/webshop/i18n/translated/de.json @@ -2825,11 +2825,11 @@ "all_providers": "Anbieter auswählen...", "all_sub_categories": "Unterkategorie auswählen...", "category": "Kategorie", - "found_for": "{{ query }}gefunden für \" \"", "funds": "Kredit", "highlighted": "Ausgewählt", "providers": "Anbieter", - "sort": "Sortieren" + "sort": "Sortieren", + "found_for": "Suchergebnisse gefunden für \"{{ query }}\"" }, "sort_by": { "created_at_asc": "Älteste zuerst", diff --git a/react/src/webshop/i18n/translated/en-US.json b/react/src/webshop/i18n/translated/en-US.json index 399695161..4deaf86f2 100644 --- a/react/src/webshop/i18n/translated/en-US.json +++ b/react/src/webshop/i18n/translated/en-US.json @@ -2944,7 +2944,7 @@ "providers": "Providers", "sort": "Sort", "all_funds": "Select credits...", - "found_for": "found for \"{{ query }}\"" + "found_for": "Search results found for \"{{ query }}\"" }, "title": "Search Results", "view": { diff --git a/react/src/webshop/i18n/translated/fr.json b/react/src/webshop/i18n/translated/fr.json index b71d3b815..88f16916d 100644 --- a/react/src/webshop/i18n/translated/fr.json +++ b/react/src/webshop/i18n/translated/fr.json @@ -2825,11 +2825,11 @@ "all_providers": "Sélectionnez le fournisseur...", "all_sub_categories": "Sélectionnez une sous-catégorie...", "category": "Catégorie", - "found_for": "{{ query }}trouvé pour \" \"", "funds": "Crédit", "highlighted": "En vedette", "providers": "Fournisseurs", - "sort": "Trier" + "sort": "Trier", + "found_for": "Résultats de la recherche pour \"{{ query }}\"" }, "sort_by": { "created_at_asc": "Le plus vieux d'abord", diff --git a/react/src/webshop/i18n/translated/pl.json b/react/src/webshop/i18n/translated/pl.json index a979c4466..ee56071a2 100644 --- a/react/src/webshop/i18n/translated/pl.json +++ b/react/src/webshop/i18n/translated/pl.json @@ -2825,11 +2825,11 @@ "all_providers": "Wybierz dostawcę...", "all_sub_categories": "Wybierz podkategorię...", "category": "Kategoria", - "found_for": "{{ query }}znaleziono dla \" \"", "funds": "Kredyt", "highlighted": "Polecane", "providers": "Dostawcy", - "sort": "Sortuj" + "sort": "Sortuj", + "found_for": "Wyniki wyszukiwania dla \"{{ query }}\"" }, "sort_by": { "created_at_asc": "Najstarszy pierwszy", diff --git a/react/src/webshop/i18n/translated/ru.json b/react/src/webshop/i18n/translated/ru.json index 62255ab80..d68a15406 100644 --- a/react/src/webshop/i18n/translated/ru.json +++ b/react/src/webshop/i18n/translated/ru.json @@ -2825,11 +2825,11 @@ "all_providers": "Выберите поставщика...", "all_sub_categories": "Выберите подкатегорию...", "category": "Категория", - "found_for": "{{ query }}найдено для \" \"", "funds": "Кредит", "highlighted": "Featured", "providers": "Провайдеры", - "sort": "Сортировать" + "sort": "Сортировать", + "found_for": "Результаты поиска, найденные для \"{{ query }}\"" }, "sort_by": { "created_at_asc": "Самый старый первый", diff --git a/react/src/webshop/i18n/translated/tr.json b/react/src/webshop/i18n/translated/tr.json index b6b18a853..7d6288c06 100644 --- a/react/src/webshop/i18n/translated/tr.json +++ b/react/src/webshop/i18n/translated/tr.json @@ -1669,11 +1669,11 @@ "all_providers": "Sağlayıcı seçin...", "all_sub_categories": "Alt kategori seçin...", "category": "Kategori", - "found_for": "{{ query }}\" \" için bulundu", "funds": "Kredi", "highlighted": "Öne Çıkanlar", "providers": "Sağlayıcılar", - "sort": "Sırala" + "sort": "Sırala", + "found_for": "\"{{ query }}\" için arama sonuçları bulundu" }, "sort_by": { "created_at_asc": "Önce en yaşlı", diff --git a/react/src/webshop/i18n/translated/uk.json b/react/src/webshop/i18n/translated/uk.json index d4436801d..9108d4ccd 100644 --- a/react/src/webshop/i18n/translated/uk.json +++ b/react/src/webshop/i18n/translated/uk.json @@ -2825,11 +2825,11 @@ "all_providers": "Виберіть провайдера...", "all_sub_categories": "Виберіть підкатегорію...", "category": "Категорія", - "found_for": "{{ query }}знайдено для \" \"", "funds": "Кредит", "highlighted": "Особливості", "providers": "Провайдери", - "sort": "Сортування" + "sort": "Сортування", + "found_for": "Результати пошуку, знайдені для \"{{ query }}\"" }, "sort_by": { "created_at_asc": "Найстарший перший", diff --git a/translations/cache/cache.json b/translations/cache/cache.json index bb34494a1..050a8e8cb 100644 --- a/translations/cache/cache.json +++ b/translations/cache/cache.json @@ -7865,7 +7865,7 @@ ], [ "search.filters.found_for", - "gevonden voor \"{{ query }}\"" + "Zoekresultaten gevonden voor \"{{ query }}\"" ], [ "search.filters.funds", From c29136abb9e33e0eabc9a359f760354b97075057 Mon Sep 17 00:00:00 2001 From: dev-rminds Date: Wed, 8 Oct 2025 18:04:08 +0300 Subject: [PATCH 5/7] improve the responsiveness of faq for small screen desktop --- .../scss/includes/blocks/block-faq.scss | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss b/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss index 0d516661f..bac9f4c14 100644 --- a/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss +++ b/react/assets/forus-webshop/scss/includes/blocks/block-faq.scss @@ -115,7 +115,15 @@ } } - @media screen and (max-width: 1000px) { + @media screen and (max-width: 1200px) { + .block-faq-header, + .block-faq-group, + .faq-item { + width: 800px; + } + } + + @media screen and (max-width: 850px) { gap: 20px; .block-faq-header { @@ -131,6 +139,10 @@ } } + .block-faq-group { + width: 100%; + } + .faq-item { width: 100%; From 9a2e08ccb47637d70f9f1fd2cb6ba695cf5d407a Mon Sep 17 00:00:00 2001 From: Yaroslav Kosterin Date: Wed, 8 Oct 2025 19:29:15 +0300 Subject: [PATCH 6/7] remove search relation for top navbar and search page, add search input on search page --- .../elements/top-navbar/TopNavbarSearch.tsx | 41 +++---------------- .../components/pages/search/Search.tsx | 33 +++++++-------- react/src/webshop/contexts/MainContext.tsx | 18 -------- react/src/webshop/i18n/nl/pages/search.mjs | 1 + 4 files changed, 21 insertions(+), 72 deletions(-) diff --git a/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx b/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx index e6959006c..313e9409d 100644 --- a/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx +++ b/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx @@ -1,5 +1,5 @@ -import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; -import { useNavigateState, useStateRoutes } from '../../../modules/state_router/Router'; +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; +import { useNavigateState } from '../../../modules/state_router/Router'; import useAppConfigs from '../../../hooks/useAppConfigs'; import { mainContext } from '../../../contexts/MainContext'; import ClickOutside from '../../../../dashboard/components/elements/click-outside/ClickOutside'; @@ -34,8 +34,7 @@ export type SearchResultLocal = { export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boolean }) { const appConfigs = useAppConfigs(); - const { route } = useStateRoutes(); - const { setShowSearchBox, searchFilter } = useContext(mainContext); + const { setShowSearchBox } = useContext(mainContext); const inputRef = useRef(null); const translate = useTranslate(); @@ -59,14 +58,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo q: '', }); - const { resetFilters, update: filterUpdate } = filters; - const { update: updateSearchFilters } = searchFilter; - - const globalQuery = useMemo(() => searchFilter?.values?.q, [searchFilter?.values?.q]); - - const isSearchResultPage = useMemo(() => { - return route.state.name === 'search-result'; - }, [route?.state?.name]); + const { resetFilters } = filters; const hideDropDown = useCallback(() => { setDropdown(false); @@ -123,10 +115,6 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo useEffect(() => { setLastQuery(filters.activeValues.q); - if (isSearchResultPage) { - return; - } - if (!filters.activeValues.q || filters.activeValues.q?.length == 0) { return clearSearch(); } @@ -136,21 +124,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo .searchWithOverview({ q: filters.activeValues.q, with_external: 1, take: 9 }) .then((res) => updateResults(res.data.data)) .finally(() => setProgress(100)); - }, [filters.activeValues.q, isSearchResultPage, searchService, clearSearch, updateResults, setProgress]); - - useEffect(() => { - let timer: number; - - if (isSearchResultPage) { - timer = window.setTimeout(() => updateSearchFilters({ q: filters.values.q })); - } - - return () => window.clearTimeout(timer); - }, [filters.values.q, isSearchResultPage, updateSearchFilters]); - - useEffect(() => { - filterUpdate({ q: globalQuery }); - }, [filterUpdate, globalQuery]); + }, [filters.activeValues.q, searchService, clearSearch, updateResults, setProgress]); return (
@@ -160,10 +134,7 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo e?.stopPropagation(); hideSearchBox(); - - if (!isSearchResultPage) { - navigateState('search-result', {}, { q: filters.values.q }); - } + navigateState('search-result', {}, { q: filters.values.q }); }} className={`search-form form ${resultsAll?.length > 0 ? 'search-form-found' : ''}`}> diff --git a/react/src/webshop/components/pages/search/Search.tsx b/react/src/webshop/components/pages/search/Search.tsx index 1f346a280..33ae76b3a 100644 --- a/react/src/webshop/components/pages/search/Search.tsx +++ b/react/src/webshop/components/pages/search/Search.tsx @@ -1,7 +1,6 @@ -import React, { Fragment, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; import useTranslate from '../../../../dashboard/hooks/useTranslate'; import useAuthIdentity from '../../../hooks/useAuthIdentity'; -import { mainContext } from '../../../contexts/MainContext'; import { SearchItem, useSearchService } from '../../../services/SearchService'; import { useFundService } from '../../../services/FundService'; import { useOrganizationService } from '../../../../dashboard/services/OrganizationService'; @@ -23,6 +22,7 @@ import { clickOnKeyEnter, clickOnKeyEnterOrSpace } from '../../../../dashboard/h import { PaginationData } from '../../../../dashboard/props/ApiResponses'; import PayoutTransaction from '../../../../dashboard/props/models/PayoutTransaction'; import usePayoutTransactionService from '../../../services/PayoutTransactionService'; +import UIControlText from '../../../../dashboard/components/elements/forms/ui-controls/UIControlText'; export default function Search() { const authIdentity = useAuthIdentity(); @@ -37,14 +37,9 @@ export default function Search() { const productCategoryService = useProductCategoryService(); const payoutTransactionService = usePayoutTransactionService(); - const { searchFilter } = useContext(mainContext); - const [displayType, setDisplayType] = useState<'list' | 'grid'>('list'); const [searchItems, setSearchItems] = useState>(null); - const globalQuery = useMemo(() => searchFilter?.values?.q, [searchFilter?.values?.q]); - const [globalInitialized, setGlobalInitialized] = useState(false); - // Search direction const [sortByOptions] = useState< Array<{ @@ -248,18 +243,6 @@ export default function Search() { ); }, [doSearch, filterValuesActive, sortByOptions]); - useEffect(() => { - setGlobalInitialized(true); - - if (!globalInitialized && filterValues?.q) { - setTimeout(() => searchFilter.update({ q: filterValues.q }), 150); - } - }, [filterValues.q, globalInitialized, searchFilter]); - - useEffect(() => { - filterUpdate({ q: globalQuery }); - }, [filterUpdate, globalQuery]); - return ( +
+ + filterUpdate({ q })} + ariaLabel={translate('search.filters.search')} + id="main_search" + /> +
+
{translate('search.filters.highlighted')}
{searchItemTypes?.map((itemType) => (
diff --git a/react/src/webshop/contexts/MainContext.tsx b/react/src/webshop/contexts/MainContext.tsx index f0d0646b9..b950d3d8c 100644 --- a/react/src/webshop/contexts/MainContext.tsx +++ b/react/src/webshop/contexts/MainContext.tsx @@ -2,9 +2,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { createContext } from 'react'; import { AppConfigProp, useConfigService } from '../../dashboard/services/ConfigService'; import EnvDataWebshopProp from '../../props/EnvDataWebshopProp'; -import useFilter from '../../dashboard/hooks/useFilter'; -import FilterScope from '../../dashboard/types/FilterScope'; -import { useStateRoutes } from '../modules/state_router/Router'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router'; import Language from '../../dashboard/props/models/Language'; @@ -20,10 +17,7 @@ interface AuthMemoProps { setMobileMenuOpened?: React.Dispatch>; userMenuOpened?: boolean; setUserMenuOpened?: React.Dispatch>; - searchQuery?: string; cookiesAccepted?: boolean; - setSearchQuery?: React.Dispatch>; - searchFilter?: FilterScope<{ q: string }>; language?: string; setLanguage?: React.Dispatch>; changeLanguage?: (locale: string) => void; @@ -43,7 +37,6 @@ const MainProvider = ({ children, cookiesAccepted }: { children: React.ReactElem const [showSearchBox, setShowSearchBox] = useState(false); const [mobileMenuOpened, setMobileMenuOpened] = useState(false); const [userMenuOpened, setUserMenuOpened] = useState(false); - const { route } = useStateRoutes(); const { i18n } = useTranslation(); const [language, setLanguage] = useState(i18n.language); @@ -51,12 +44,6 @@ const MainProvider = ({ children, cookiesAccepted }: { children: React.ReactElem return appConfigs?.languages; }, [appConfigs?.languages]); - const searchFilter = useFilter({ - q: '', - }); - - const { update: searchFilterUpdate } = searchFilter; - const changeLanguage = useCallback( (lang: string) => { setLanguage(lang); @@ -82,10 +69,6 @@ const MainProvider = ({ children, cookiesAccepted }: { children: React.ReactElem }); }, [configService, envData?.type]); - useEffect(() => { - searchFilterUpdate({ q: '' }); - }, [route.pathname, route?.state?.name, searchFilterUpdate]); - return ( Date: Thu, 9 Oct 2025 07:31:23 +0300 Subject: [PATCH 7/7] update translations, improve dismissal of search dropdown when navigating to search page quickly --- .../elements/top-navbar/TopNavbarSearch.tsx | 50 +++++++++++++++++-- .../components/pages/search/Search.tsx | 1 + react/src/webshop/i18n/translated/ar.json | 3 +- react/src/webshop/i18n/translated/de.json | 3 +- react/src/webshop/i18n/translated/en-US.json | 3 +- react/src/webshop/i18n/translated/fr.json | 3 +- react/src/webshop/i18n/translated/pl.json | 3 +- react/src/webshop/i18n/translated/ru.json | 3 +- react/src/webshop/i18n/translated/tr.json | 3 +- react/src/webshop/i18n/translated/uk.json | 3 +- translations/cache/cache.json | 4 ++ 11 files changed, 66 insertions(+), 13 deletions(-) diff --git a/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx b/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx index 313e9409d..29e6c47bd 100644 --- a/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx +++ b/react/src/webshop/components/elements/top-navbar/TopNavbarSearch.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; -import { useNavigateState } from '../../../modules/state_router/Router'; +import { useNavigateState, useStateRoutes } from '../../../modules/state_router/Router'; import useAppConfigs from '../../../hooks/useAppConfigs'; import { mainContext } from '../../../contexts/MainContext'; import ClickOutside from '../../../../dashboard/components/elements/click-outside/ClickOutside'; @@ -21,6 +21,8 @@ import TopNavbarSearchResultItem from './TopNavbarSearchResultItem'; import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; import { clickOnKeyEnter } from '../../../../dashboard/helpers/wcag'; import classNames from 'classnames'; +import { ResponseError } from '../../../../dashboard/props/ApiResponses'; +import usePushDanger from '../../../../dashboard/hooks/usePushDanger'; export type SearchResultGroupLocal = SearchResultGroup & { shown?: boolean; @@ -41,10 +43,15 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo const navigateState = useNavigateState(); const searchService = useSearchService(); + const pushDanger = usePushDanger(); const setProgress = useSetProgress(); + const hideSearchDropdown = useRef(false); + const searchingForDropdown = useRef(false); + const [dropdown, setDropdown] = useState(false); const [searchFocused, setSearchFocused] = useState(false); + const { route: currentState } = useStateRoutes(); const [results, setResults] = useState(null); const [resultsAll, setResultsAll] = useState>(null); @@ -118,13 +125,41 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo if (!filters.activeValues.q || filters.activeValues.q?.length == 0) { return clearSearch(); } + setProgress(0); + searchingForDropdown.current = true; searchService .searchWithOverview({ q: filters.activeValues.q, with_external: 1, take: 9 }) - .then((res) => updateResults(res.data.data)) - .finally(() => setProgress(100)); - }, [filters.activeValues.q, searchService, clearSearch, updateResults, setProgress]); + .then((res) => { + updateResults(res.data.data); + + if (hideSearchDropdown.current) { + hideDropDown(); + } + }) + .catch((err: ResponseError) => { + pushDanger(translate('push.error'), err.data?.message); + }) + .finally(() => { + setProgress(100); + hideSearchDropdown.current = false; + searchingForDropdown.current = false; + }); + }, [ + filters.activeValues.q, + searchService, + clearSearch, + updateResults, + setProgress, + hideDropDown, + pushDanger, + translate, + ]); + + useEffect(() => { + clearSearch(); + }, [currentState?.state?.name, clearSearch]); return (
@@ -133,8 +168,13 @@ export default function TopNavbarSearch({ autoFocus = false }: { autoFocus?: boo e?.preventDefault(); e?.stopPropagation(); - hideSearchBox(); + clearSearch(); + if (searchingForDropdown.current) { + hideSearchDropdown.current = true; + } + navigateState('search-result', {}, { q: filters.values.q }); + document.querySelector('#main_search')?.focus(); }} className={`search-form form ${resultsAll?.length > 0 ? 'search-form-found' : ''}`}> diff --git a/react/src/webshop/components/pages/search/Search.tsx b/react/src/webshop/components/pages/search/Search.tsx index 33ae76b3a..5f209e854 100644 --- a/react/src/webshop/components/pages/search/Search.tsx +++ b/react/src/webshop/components/pages/search/Search.tsx @@ -262,6 +262,7 @@ export default function Search() { filterUpdate({ q })} ariaLabel={translate('search.filters.search')} id="main_search" diff --git a/react/src/webshop/i18n/translated/ar.json b/react/src/webshop/i18n/translated/ar.json index 329f0328f..70e3239df 100644 --- a/react/src/webshop/i18n/translated/ar.json +++ b/react/src/webshop/i18n/translated/ar.json @@ -1673,7 +1673,8 @@ "highlighted": "مميز", "providers": "المزودون", "sort": "فرز", - "found_for": "تم العثور على نتائج البحث عن \"{{ query }}\"" + "found_for": "تم العثور على نتائج البحث عن \"{{ query }}\"", + "search": "بحث" }, "sort_by": { "created_at_asc": "الأقدم أولاً", diff --git a/react/src/webshop/i18n/translated/de.json b/react/src/webshop/i18n/translated/de.json index b7aa445ac..64be7c08a 100644 --- a/react/src/webshop/i18n/translated/de.json +++ b/react/src/webshop/i18n/translated/de.json @@ -2829,7 +2829,8 @@ "highlighted": "Ausgewählt", "providers": "Anbieter", "sort": "Sortieren", - "found_for": "Suchergebnisse gefunden für \"{{ query }}\"" + "found_for": "Suchergebnisse gefunden für \"{{ query }}\"", + "search": "Suche" }, "sort_by": { "created_at_asc": "Älteste zuerst", diff --git a/react/src/webshop/i18n/translated/en-US.json b/react/src/webshop/i18n/translated/en-US.json index 4deaf86f2..3d1296f4e 100644 --- a/react/src/webshop/i18n/translated/en-US.json +++ b/react/src/webshop/i18n/translated/en-US.json @@ -2944,7 +2944,8 @@ "providers": "Providers", "sort": "Sort", "all_funds": "Select credits...", - "found_for": "Search results found for \"{{ query }}\"" + "found_for": "Search results found for \"{{ query }}\"", + "search": "Search" }, "title": "Search Results", "view": { diff --git a/react/src/webshop/i18n/translated/fr.json b/react/src/webshop/i18n/translated/fr.json index 88f16916d..d7878c131 100644 --- a/react/src/webshop/i18n/translated/fr.json +++ b/react/src/webshop/i18n/translated/fr.json @@ -2829,7 +2829,8 @@ "highlighted": "En vedette", "providers": "Fournisseurs", "sort": "Trier", - "found_for": "Résultats de la recherche pour \"{{ query }}\"" + "found_for": "Résultats de la recherche pour \"{{ query }}\"", + "search": "Recherche" }, "sort_by": { "created_at_asc": "Le plus vieux d'abord", diff --git a/react/src/webshop/i18n/translated/pl.json b/react/src/webshop/i18n/translated/pl.json index ee56071a2..faf753ca2 100644 --- a/react/src/webshop/i18n/translated/pl.json +++ b/react/src/webshop/i18n/translated/pl.json @@ -2829,7 +2829,8 @@ "highlighted": "Polecane", "providers": "Dostawcy", "sort": "Sortuj", - "found_for": "Wyniki wyszukiwania dla \"{{ query }}\"" + "found_for": "Wyniki wyszukiwania dla \"{{ query }}\"", + "search": "Wyszukiwanie" }, "sort_by": { "created_at_asc": "Najstarszy pierwszy", diff --git a/react/src/webshop/i18n/translated/ru.json b/react/src/webshop/i18n/translated/ru.json index d68a15406..0cd09ebf6 100644 --- a/react/src/webshop/i18n/translated/ru.json +++ b/react/src/webshop/i18n/translated/ru.json @@ -2829,7 +2829,8 @@ "highlighted": "Featured", "providers": "Провайдеры", "sort": "Сортировать", - "found_for": "Результаты поиска, найденные для \"{{ query }}\"" + "found_for": "Результаты поиска, найденные для \"{{ query }}\"", + "search": "Поиск" }, "sort_by": { "created_at_asc": "Самый старый первый", diff --git a/react/src/webshop/i18n/translated/tr.json b/react/src/webshop/i18n/translated/tr.json index 7d6288c06..37f039d11 100644 --- a/react/src/webshop/i18n/translated/tr.json +++ b/react/src/webshop/i18n/translated/tr.json @@ -1673,7 +1673,8 @@ "highlighted": "Öne Çıkanlar", "providers": "Sağlayıcılar", "sort": "Sırala", - "found_for": "\"{{ query }}\" için arama sonuçları bulundu" + "found_for": "\"{{ query }}\" için arama sonuçları bulundu", + "search": "Arama" }, "sort_by": { "created_at_asc": "Önce en yaşlı", diff --git a/react/src/webshop/i18n/translated/uk.json b/react/src/webshop/i18n/translated/uk.json index 9108d4ccd..a46ab2979 100644 --- a/react/src/webshop/i18n/translated/uk.json +++ b/react/src/webshop/i18n/translated/uk.json @@ -2829,7 +2829,8 @@ "highlighted": "Особливості", "providers": "Провайдери", "sort": "Сортування", - "found_for": "Результати пошуку, знайдені для \"{{ query }}\"" + "found_for": "Результати пошуку, знайдені для \"{{ query }}\"", + "search": "Пошук" }, "sort_by": { "created_at_asc": "Найстарший перший", diff --git a/translations/cache/cache.json b/translations/cache/cache.json index 050a8e8cb..2de049af8 100644 --- a/translations/cache/cache.json +++ b/translations/cache/cache.json @@ -7879,6 +7879,10 @@ "search.filters.providers", "Aanbieders" ], + [ + "search.filters.search", + "Zoek" + ], [ "search.filters.sort", "Sorteer"