Initial commit

This commit is contained in:
Nikolay Pecheniev
2026-02-03 14:00:33 +02:00
commit 99c8d86086
577 changed files with 75868 additions and 0 deletions

39
src/hooks/useBlogPosts.ts Normal file
View File

@@ -0,0 +1,39 @@
"use client";
import { useEffect, useState } from "react";
import { BlogPost, defaultPosts, fetchBlogPosts } from "@/lib/api/blog";
export function useBlogPosts() {
const [posts, setPosts] = useState<BlogPost[]>(defaultPosts);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let isMounted = true;
async function loadPosts() {
try {
const data = await fetchBlogPosts();
if (isMounted) {
setPosts(data);
}
} catch (err) {
if (isMounted) {
setError(err instanceof Error ? err : new Error("Failed to fetch posts"));
}
} finally {
if (isMounted) {
setIsLoading(false);
}
}
}
loadPosts();
return () => {
isMounted = false;
};
}, []);
return { posts, isLoading, error };
}

View File

@@ -0,0 +1,38 @@
import { useEffect, RefObject } from "react";
export const useClickOutside = (
ref: RefObject<HTMLElement | null>,
handler: () => void,
isActive: boolean = true,
excludeRefs?: RefObject<HTMLElement | null>[]
) => {
useEffect(() => {
if (!isActive) return;
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
const isExcluded = excludeRefs?.some((excludeRef) =>
excludeRef.current?.contains(event.target as Node)
);
if (!isExcluded) {
handler();
}
}
};
const handleEscape = (event: KeyboardEvent) => {
if (event.key === "Escape") {
handler();
}
};
document.addEventListener("click", handleClickOutside);
document.addEventListener("keydown", handleEscape);
return () => {
document.removeEventListener("click", handleClickOutside);
document.removeEventListener("keydown", handleEscape);
};
}, [ref, handler, isActive, excludeRefs]);
};

39
src/hooks/useProducts.ts Normal file
View File

@@ -0,0 +1,39 @@
"use client";
import { useEffect, useState } from "react";
import { Product, fetchProducts } from "@/lib/api/product";
export function useProducts() {
const [products, setProducts] = useState<Product[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let isMounted = true;
async function loadProducts() {
try {
const data = await fetchProducts();
if (isMounted) {
setProducts(data);
}
} catch (err) {
if (isMounted) {
setError(err instanceof Error ? err : new Error("Failed to fetch products"));
}
} finally {
if (isMounted) {
setIsLoading(false);
}
}
}
loadProducts();
return () => {
isMounted = false;
};
}, []);
return { products, isLoading, error };
}