feat: add Zustand stores and custom hooks
This commit is contained in:
@@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
export function useDebounce<T>(value: T, delay: number): T {
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setDebouncedValue(value);
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
};
|
||||||
|
}, [value, delay]);
|
||||||
|
|
||||||
|
return debouncedValue;
|
||||||
|
}
|
||||||
@@ -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<void>;
|
||||||
|
logout: () => Promise<void>;
|
||||||
|
checkAuth: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAuthStore = create<AuthState>((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
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}));
|
||||||
@@ -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<SearchState>((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 }),
|
||||||
|
}));
|
||||||
Reference in New Issue
Block a user