From 57054efe7620e0e0117aec71e57b29b311fc698a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoni=20Nu=C3=B1ez=20Romeu?= Date: Mon, 6 Jul 2026 11:03:55 +0200 Subject: [PATCH] feat: add Zustand stores and custom hooks --- frontend-mobile/hooks/useAuth.ts | 19 ++++++++++++++ frontend-mobile/hooks/useDebounce.ts | 17 +++++++++++++ frontend-mobile/store/authStore.ts | 38 ++++++++++++++++++++++++++++ frontend-mobile/store/searchStore.ts | 27 ++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 frontend-mobile/hooks/useAuth.ts create mode 100644 frontend-mobile/hooks/useDebounce.ts create mode 100644 frontend-mobile/store/authStore.ts create mode 100644 frontend-mobile/store/searchStore.ts diff --git a/frontend-mobile/hooks/useAuth.ts b/frontend-mobile/hooks/useAuth.ts new file mode 100644 index 0000000..644092c --- /dev/null +++ b/frontend-mobile/hooks/useAuth.ts @@ -0,0 +1,19 @@ +import { useEffect } from 'react'; +import { useAuthStore } from '../store/authStore'; + +export function useAuth() { + const { user, isLoading, isAuthenticated, login, logout, checkAuth } = useAuthStore(); + + useEffect(() => { + checkAuth(); + }, []); + + return { + user, + isLoading, + isAuthenticated, + login, + logout, + isAdmin: user?.is_admin ?? false, + }; +} diff --git a/frontend-mobile/hooks/useDebounce.ts b/frontend-mobile/hooks/useDebounce.ts new file mode 100644 index 0000000..0a45ef2 --- /dev/null +++ b/frontend-mobile/hooks/useDebounce.ts @@ -0,0 +1,17 @@ +import { useState, useEffect } from 'react'; + +export function useDebounce(value: T, delay: number): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(timer); + }; + }, [value, delay]); + + return debouncedValue; +} diff --git a/frontend-mobile/store/authStore.ts b/frontend-mobile/store/authStore.ts new file mode 100644 index 0000000..5e125be --- /dev/null +++ b/frontend-mobile/store/authStore.ts @@ -0,0 +1,38 @@ +import { create } from 'zustand'; +import { User } from '../types'; +import * as authService from '../services/auth'; + +interface AuthState { + user: User | null; + isLoading: boolean; + isAuthenticated: boolean; + login: (username: string, password: string) => Promise; + logout: () => Promise; + checkAuth: () => Promise; +} + +export const useAuthStore = create((set) => ({ + user: null, + isLoading: true, + isAuthenticated: false, + + login: async (username: string, password: string) => { + const { user } = await authService.login(username, password); + set({ user, isAuthenticated: true }); + }, + + logout: async () => { + await authService.logout(); + set({ user: null, isAuthenticated: false }); + }, + + checkAuth: async () => { + set({ isLoading: true }); + const user = await authService.checkAuth() || await authService.getStoredUser(); + set({ + user, + isAuthenticated: !!user, + isLoading: false + }); + }, +})); diff --git a/frontend-mobile/store/searchStore.ts b/frontend-mobile/store/searchStore.ts new file mode 100644 index 0000000..1276c23 --- /dev/null +++ b/frontend-mobile/store/searchStore.ts @@ -0,0 +1,27 @@ +import { create } from 'zustand'; +import { Medicine } from '../types'; + +interface SearchState { + query: string; + results: Medicine[]; + isLoading: boolean; + error: string | null; + setQuery: (query: string) => void; + setResults: (results: Medicine[]) => void; + setLoading: (loading: boolean) => void; + setError: (error: string | null) => void; + clearResults: () => void; +} + +export const useSearchStore = create((set) => ({ + query: '', + results: [], + isLoading: false, + error: null, + + setQuery: (query) => set({ query }), + setResults: (results) => set({ results, isLoading: false }), + setLoading: (isLoading) => set({ isLoading }), + setError: (error) => set({ error, isLoading: false }), + clearResults: () => set({ results: [], query: '', error: null }), +}));