From 85fc1ede1555444aef3e7c6245fbf56c13259a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoni=20Nu=C3=B1ez=20Romeu?= Date: Fri, 17 Jul 2026 15:15:18 +0200 Subject: [PATCH] fix: resolve {{count}} interpolation and add notification bell for parapharmacy products - Add interpolation support to t() function in LanguageContext (web + mobile) - Pass medicine, currentUser, onLoginRequest props to PharmacyList in ProductView - Remove duplicate title in ProductView (PharmacyList already renders one) --- apps/frontend-mobile/src/i18n/LanguageContext.jsx | 10 ++++++++-- apps/frontend/src/App.jsx | 2 ++ apps/frontend/src/i18n/LanguageContext.jsx | 10 ++++++++-- apps/frontend/src/views/ProductView.jsx | 9 ++++----- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/apps/frontend-mobile/src/i18n/LanguageContext.jsx b/apps/frontend-mobile/src/i18n/LanguageContext.jsx index a5058ad..0e26784 100644 --- a/apps/frontend-mobile/src/i18n/LanguageContext.jsx +++ b/apps/frontend-mobile/src/i18n/LanguageContext.jsx @@ -36,8 +36,14 @@ export function LanguageProvider({ children }) { AsyncStorage.setItem(STORAGE_KEY, newLang).catch(() => {}); }, []); - const t = useCallback((key) => { - return locales[lang]?.[key] || locales.es[key] || key; + const t = useCallback((key, params) => { + let str = locales[lang]?.[key] || locales.es[key] || key; + if (params && typeof str === 'string') { + Object.keys(params).forEach((k) => { + str = str.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), params[k]); + }); + } + return str; }, [lang]); const value = useMemo(() => ({ lang, setLang, t, ready }), [lang, setLang, t, ready]); diff --git a/apps/frontend/src/App.jsx b/apps/frontend/src/App.jsx index 30c3497..fb54552 100644 --- a/apps/frontend/src/App.jsx +++ b/apps/frontend/src/App.jsx @@ -195,6 +195,8 @@ function App() { source={productScreen?.source} id={productScreen?.id} onBack={() => { setProductScreen(null); setScreen('search'); }} + currentUser={currentUser} + onLoginRequest={() => setShowLogin(true)} /> ); break; diff --git a/apps/frontend/src/i18n/LanguageContext.jsx b/apps/frontend/src/i18n/LanguageContext.jsx index eca5b42..0777499 100644 --- a/apps/frontend/src/i18n/LanguageContext.jsx +++ b/apps/frontend/src/i18n/LanguageContext.jsx @@ -26,8 +26,14 @@ export function LanguageProvider({ children }) { } catch {} }, []); - const t = useCallback((key) => { - return locales[lang]?.[key] || locales.es[key] || key; + const t = useCallback((key, params) => { + let str = locales[lang]?.[key] || locales.es[key] || key; + if (params && typeof str === 'string') { + Object.keys(params).forEach((k) => { + str = str.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), params[k]); + }); + } + return str; }, [lang]); const value = useMemo(() => ({ lang, setLang, t }), [lang, setLang, t]); diff --git a/apps/frontend/src/views/ProductView.jsx b/apps/frontend/src/views/ProductView.jsx index cc4553b..51602ed 100644 --- a/apps/frontend/src/views/ProductView.jsx +++ b/apps/frontend/src/views/ProductView.jsx @@ -5,7 +5,7 @@ import { haversineKm, getUserPosition, hasCachedPosition } from '../utils/geo'; import { useTranslation } from '../i18n'; import './ProductView.css'; -export default function ProductView({ source, id, onBack }) { +export default function ProductView({ source, id, onBack, currentUser, onLoginRequest }) { const { t } = useTranslation(); const [product, setProduct] = useState(null); const [loading, setLoading] = useState(true); @@ -196,10 +196,6 @@ export default function ProductView({ source, id, onBack }) {
{t('productView.loadingPharmacies')}
) : pharmacies.length > 0 ? ( <> -

- {t('productView.availableInPharmacies', { count: pharmacies.length })} -

-