From 2d702c65852046ea5cec02323851d6ac9305f134 Mon Sep 17 00:00:00 2001 From: arcadio77 <66469918+arcadio77@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:21:20 +0100 Subject: [PATCH 1/2] fix --- src/api/cms-service.ts | 8 ------ src/api/product-service.ts | 13 ---------- src/api/statistics-service.ts | 13 ---------- src/components/common/Header.tsx | 7 ----- src/contexts/CartProvider.tsx | 22 ---------------- src/contexts/IndividualUserProvider.tsx | 4 --- src/hooks/useCheckout.ts | 20 +-------------- src/hooks/usePayment.ts | 4 --- src/hooks/useProductPage.ts | 12 --------- src/pages/CartPage.tsx | 2 -- src/pages/Contact.tsx | 3 --- src/pages/Faq.tsx | 4 --- src/pages/Login.tsx | 1 - src/pages/OrderConfirmationPage.tsx | 2 -- src/pages/PaymentPage.tsx | 3 --- src/pages/ProductPage.tsx | 3 --- src/pages/admin/AddProductPage.tsx | 12 +++------ src/pages/admin/CategoryManagementPage.tsx | 3 --- src/pages/admin/ContactPageEditor.tsx | 5 ---- src/pages/admin/FaqPageEditor.tsx | 5 ---- src/pages/admin/HomePageEditor.tsx | 30 ---------------------- 21 files changed, 4 insertions(+), 172 deletions(-) diff --git a/src/api/cms-service.ts b/src/api/cms-service.ts index 610affb..b2f186b 100644 --- a/src/api/cms-service.ts +++ b/src/api/cms-service.ts @@ -6,8 +6,6 @@ import type { } from "../types/cms"; import { API_BASE_URL, apiCall } from "./utils"; -// ==================== HOME PAGE ==================== - export const fetchHomeSettings = async (): Promise => { try { const response = await apiCall(`${API_BASE_URL}/api/settings/home`, { @@ -54,8 +52,6 @@ export const saveHomeSettings = async (settings: HomePageContent): Promise } }; -// ==================== FAQ PAGE ==================== - export const fetchFaqSettings = async (): Promise => { try { const response = await apiCall(`${API_BASE_URL}/api/settings/faq`, { @@ -102,8 +98,6 @@ export const saveFaqSettings = async (settings: FaqPageContent): Promise = } }; -// ==================== CONTACT PAGE ==================== - export const fetchContactSettings = async (): Promise => { try { const response = await apiCall(`${API_BASE_URL}/api/settings/contact`, { @@ -152,8 +146,6 @@ export const saveContactSettings = async (settings: ContactPageContent): Promise } }; -// ==================== LEGACY GLOBAL SETTINGS (deprecated) ==================== - export const fetchGlobalSettings = async (): Promise => { const jwtToken = localStorage.getItem("token"); diff --git a/src/api/product-service.ts b/src/api/product-service.ts index 3b9a820..fb91c5b 100644 --- a/src/api/product-service.ts +++ b/src/api/product-service.ts @@ -67,7 +67,6 @@ export const getRootCategories = async (): Promise => { } }; -// Get all categories (flat list) export const getAllCategories = async (): Promise => { try { const response = await apiCall(CATEGORY_API, { @@ -85,7 +84,6 @@ export const getAllCategories = async (): Promise => { } }; -// Get subcategories of a specific category export const getSubcategories = async (categoryId: string): Promise => { try { const response = await apiCall(`${CATEGORY_API}/${categoryId}/subcategories`, { @@ -103,7 +101,6 @@ export const getSubcategories = async (categoryId: string): Promise => { try { const response = await apiCall(`${CATEGORY_API}/${categoryId}`, { @@ -121,11 +118,6 @@ export const getCategoryById = async (categoryId: string): Promise => { @@ -146,8 +138,6 @@ export const createCategory = async ( } }; -// Update category (name and/or parent) -// Note: This endpoint is not yet implemented in CategoryController, only in service export const updateCategory = async ( categoryId: string, categoryData: CategoryUpdateRequestDTO, @@ -169,9 +159,6 @@ export const updateCategory = async ( } }; -// Delete category -// Note: This endpoint is not yet implemented in CategoryController, only in service -// When implemented, subcategories will be moved to the parent of deleted category export const deleteCategory = async (categoryId: string): Promise => { try { const response = await apiCall(`${CATEGORY_API}/${categoryId}`, { diff --git a/src/api/statistics-service.ts b/src/api/statistics-service.ts index 4e14aaf..fb5387f 100644 --- a/src/api/statistics-service.ts +++ b/src/api/statistics-service.ts @@ -10,19 +10,11 @@ import { apiCall } from "./utils"; const STATISTICS_SERVICE_URL = "http://localhost:8700"; const STATISTICS_API = `${STATISTICS_SERVICE_URL}/api/statistics`; -/** - * Get all available variants with their sales and stock data status - */ export const getAvailableVariants = async (): Promise => { const response = await apiCall(`${STATISTICS_API}/variants`); return await response.json(); }; -/** - * Get sales data over time for a specific variant - * @param variantId - UUID of the variant - * @param filters - Optional date range and trend configuration - */ export const getVariantSalesOverTime = async ( variantId: string, filters?: SalesFilters, @@ -44,11 +36,6 @@ export const getVariantSalesOverTime = async ( return await response.json(); }; -/** - * Get stock level data over time for a specific variant - * @param variantId - UUID of the variant - * @param filters - Optional date range and trend configuration - */ export const getVariantStockOverTime = async ( variantId: string, filters?: StockFilters, diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx index 6c3f960..104235f 100644 --- a/src/components/common/Header.tsx +++ b/src/components/common/Header.tsx @@ -84,7 +84,6 @@ const Header: React.FC = ({ minimalist }) => { const cartItemsCount = cartItems.reduce((sum, item) => sum + item.quantity, 0); - // Prefetch HomePage data when not on homepage useEffect(() => { if (location.pathname !== "/") { const prefetchHomeData = async () => { @@ -93,11 +92,9 @@ const Header: React.FC = ({ minimalist }) => { const CACHE_KEY_CATEGORIES = "homepage_categories"; const CACHE_DURATION = 5 * 60 * 1000; - // Check cache const cachedHome = sessionStorage.getItem(CACHE_KEY_HOME); const cachedCategories = sessionStorage.getItem(CACHE_KEY_CATEGORIES); - // Prefetch only if there's no cache or cache is old if (!cachedHome || Date.now() - JSON.parse(cachedHome).timestamp > CACHE_DURATION) { fetchHomeSettings().then((data) => { sessionStorage.setItem( @@ -119,11 +116,9 @@ const Header: React.FC = ({ minimalist }) => { }); } } catch { - // Ignore prefetch errors } }; - // Prefetch after a short delay to avoid blocking main rendering const timeoutId = setTimeout(prefetchHomeData, 1000); return () => clearTimeout(timeoutId); } @@ -523,7 +518,6 @@ const Header: React.FC = ({ minimalist }) => { - {/* User menu */} = ({ minimalist }) => { }, }} > - {/* User Panel */} { - // Don't refetch if cart was manually cleared if (hasBeenCleared) { return; } - // Check if token exists before trying to fetch cart const token = localStorage.getItem("token"); if (!token) { setCartItems([]); @@ -37,11 +35,9 @@ export default function CartProvider({ children }: { children: ReactNode }) { const fetchedCart = await fetchCartProducts(); const rawItems = fetchedCart.productDtos || []; - // Map each cart item (productId is variantId) to CartItem by fetching variant details const completeItems: CartItem[] = await Promise.all( rawItems.map(async (rawItem) => { try { - // productId in cart is actually variantId const variantDetails = await getVariantDetails(rawItem.productId); const variant = variantDetails.variant; const mainImage = @@ -59,7 +55,6 @@ export default function CartProvider({ children }: { children: ReactNode }) { `Failed to fetch variant details for variantId ${rawItem.productId}:`, err, ); - // Return a placeholder item if variant fetch fails return { id: rawItem.productId, name: `Product ${rawItem.productId}`, @@ -74,8 +69,6 @@ export default function CartProvider({ children }: { children: ReactNode }) { setCartItems(completeItems); } catch (err) { console.error("Error fetching cart:", err); - // Only set error if token exists (user is logged in) - // If token doesn't exist, it's not an error - just empty cart if (token) { setError("Failed to fetch cart items"); } else { @@ -89,15 +82,12 @@ export default function CartProvider({ children }: { children: ReactNode }) { const removeProduct = useCallback( async (productId: string) => { - // Optimistic update setCartItems((prevItems) => prevItems.filter((item) => item.id !== productId)); try { await deleteCartProduct(productId); - // No refetch needed - optimistic update is sufficient } catch (err) { console.error("Error removing product:", err); - // Revert optimistic update on error await refetchCart(); throw new Error("Failed to remove product from cart."); } @@ -113,7 +103,6 @@ export default function CartProvider({ children }: { children: ReactNode }) { return; } - // Optimistic update setCartItems((prevItems) => prevItems.map((item) => item.id === productId ? { ...item, quantity: newQuantity } : item, @@ -126,10 +115,8 @@ export default function CartProvider({ children }: { children: ReactNode }) { } else { await subtractCartProduct(productId, 1); } - // No refetch needed - optimistic update is sufficient } catch (err) { console.error("Error updating quantity:", err); - // Revert optimistic update on error await refetchCart(); throw new Error("Failed to update quantity in cart."); } @@ -144,7 +131,6 @@ export default function CartProvider({ children }: { children: ReactNode }) { return; } - // Optimistic update setCartItems((prevItems) => prevItems.map((item) => item.id === productId ? { ...item, quantity: newQuantity } : item, @@ -153,10 +139,8 @@ export default function CartProvider({ children }: { children: ReactNode }) { try { await overwriteCartProduct(productId, newQuantity); - // No refetch needed - optimistic update is sufficient } catch (err) { console.error("Error updating quantity:", err); - // Revert optimistic update on error await refetchCart(); throw new Error("Failed to update quantity in cart."); } @@ -170,25 +154,19 @@ export default function CartProvider({ children }: { children: ReactNode }) { await clearCart(cartItems.map((item) => item.id)); }, [cartItems]); - // Initial fetch on mount useEffect(() => { refetchCart(); - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - // Listen for token changes (login/logout) useEffect(() => { const handleStorageChange = (e: StorageEvent) => { if (e.key === "token") { - // Token was added or removed, refetch cart refetchCart(); } }; - // Listen for storage events (works across tabs) window.addEventListener("storage", handleStorageChange); - // Also listen for custom event (for same-tab token changes) const handleTokenChange = () => { refetchCart(); }; diff --git a/src/contexts/IndividualUserProvider.tsx b/src/contexts/IndividualUserProvider.tsx index 35e858b..39844e3 100644 --- a/src/contexts/IndividualUserProvider.tsx +++ b/src/contexts/IndividualUserProvider.tsx @@ -23,7 +23,6 @@ export default function IndividualUserProvider({ children }: { children: ReactNo return; } - // Extract permissions from token const perms = getPermissionsFromToken(token); setPermissions(perms); localStorage.setItem("permissions", JSON.stringify(perms)); @@ -37,12 +36,10 @@ export default function IndividualUserProvider({ children }: { children: ReactNo console.error("Error fetching current user:", err); setError("Failed to load user data."); setCurrentUser(null); - // If token is invalid, remove it if (err instanceof Error && err.message.includes("401")) { localStorage.removeItem("token"); localStorage.removeItem("permissions"); setPermissions([]); - // Dispatch custom event to notify CartProvider about token removal window.dispatchEvent(new Event("token-changed")); } } finally { @@ -81,7 +78,6 @@ export default function IndividualUserProvider({ children }: { children: ReactNo setCurrentUser(null); setPermissions([]); setError(null); - // Dispatch custom event to notify CartProvider about token removal window.dispatchEvent(new Event("token-changed")); }, []); diff --git a/src/hooks/useCheckout.ts b/src/hooks/useCheckout.ts index 05ce43e..d434ff9 100644 --- a/src/hooks/useCheckout.ts +++ b/src/hooks/useCheckout.ts @@ -37,7 +37,6 @@ interface CheckoutStorageData { isDiscountApplied: boolean; } -// Helper function to load data from sessionStorage const loadCheckoutDataFromStorage = ( orderId: string | null, ): Partial | null => { @@ -60,7 +59,6 @@ export const useCheckout = (initialOrderId?: string) => { const { cartItems } = useCartContext(); const navigate = useNavigate(); - // Load data from sessionStorage synchronously on initialization const savedData = loadCheckoutDataFromStorage(initialOrderId || null); const [shippingModalOpen, setShippingModalOpen] = useState(false); @@ -81,18 +79,14 @@ export const useCheckout = (initialOrderId?: string) => { ); const [orderId, setOrderId] = useState(initialOrderId || null); - // Use orderId from URL if provided and load data from storage useEffect(() => { if (initialOrderId) { - // Set orderId if not already set if (!orderId) { setOrderId(initialOrderId); } - // Load data from storage when initialOrderId changes (e.g., when returning from PaymentPage) const newSavedData = loadCheckoutDataFromStorage(initialOrderId); if (newSavedData) { - // Update only if data is different from current (avoid unnecessary updates) if ( newSavedData.shippingData && JSON.stringify(newSavedData.shippingData) !== JSON.stringify(shippingData) @@ -124,18 +118,14 @@ export const useCheckout = (initialOrderId?: string) => { } }, [initialOrderId]); // eslint-disable-line react-hooks/exhaustive-deps - // Save data to sessionStorage when it changes (but not on first render if data is already in storage) useEffect(() => { if (orderId) { - // Check if this is the first render with data from storage const storageKey = getStorageKey(orderId); const existingData = sessionStorage.getItem(storageKey); - // If data already exists and is the same as current, don't save (avoid unnecessary saves) if (existingData) { try { const parsed: CheckoutStorageData = JSON.parse(existingData); - // Compare only key fields to avoid saving if nothing changed if ( JSON.stringify(parsed.shippingData) === JSON.stringify(shippingData) && JSON.stringify(parsed.invoiceData) === JSON.stringify(invoiceData) && @@ -144,10 +134,9 @@ export const useCheckout = (initialOrderId?: string) => { parsed.discountCode === discountCode && parsed.isDiscountApplied === isDiscountApplied ) { - return; // Don't save if data is identical + return; } } catch { - // If cannot parse, save new data } } @@ -196,13 +185,11 @@ export const useCheckout = (initialOrderId?: string) => { const handleShippingSubmit = (values: ShippingFormValues) => { setShippingData(values); setShippingModalOpen(false); - // Data will be automatically saved by useEffect }; const handleInvoiceSubmit = (values: InvoiceFormValues) => { setInvoiceData(values); setInvoiceModalOpen(false); - // Data will be automatically saved by useEffect }; const handleInvoiceChange = (checked: boolean) => { @@ -241,11 +228,9 @@ export const useCheckout = (initialOrderId?: string) => { } if (paymentMethod === "card") { - // Redirect to card payment page with orderId in URL const paymentId = crypto.randomUUID(); navigate(`/payment/${paymentId}/${orderId}`); } else { - // Cash on delivery - redirect directly to confirmation with token const confirmationToken = crypto.randomUUID(); navigate(`/order-confirmation/${orderId}/${confirmationToken}`); } @@ -279,7 +264,6 @@ export const useCheckout = (initialOrderId?: string) => { }; return { - // State shippingModalOpen, invoiceModalOpen, wantsInvoice, @@ -297,13 +281,11 @@ export const useCheckout = (initialOrderId?: string) => { discountError, canPay: !!shippingData.firstName, - // Setters setShippingModalOpen, setInvoiceModalOpen, setPaymentMethod, setDiscountCode, - // Handlers handleShippingSubmit, handleInvoiceSubmit, handleInvoiceChange, diff --git a/src/hooks/usePayment.ts b/src/hooks/usePayment.ts index ee96d26..0575a2c 100644 --- a/src/hooks/usePayment.ts +++ b/src/hooks/usePayment.ts @@ -36,12 +36,10 @@ export const usePayment = () => { const total = useMemo(() => subtotal + shipping, [subtotal, shipping]); const validateCard = (values: CardFormValues): boolean => { - // Normalize data for comparison const normalizedCardNumber = values.cardNumber.replace(/\s/g, ""); const normalizedExpiry = values.expiryDate.replace(/\//g, ""); const normalizedName = values.cardholderName.toUpperCase().trim(); - // Check if card matches the mocked one if ( normalizedCardNumber === VALID_CARD.cardNumber && normalizedExpiry === VALID_CARD.expiryDate.replace(/\//g, "") && @@ -59,7 +57,6 @@ export const usePayment = () => { setPaymentError(null); try { - // Simulate delay await new Promise((resolve) => setTimeout(resolve, 1000)); if (!validateCard(values)) { @@ -68,7 +65,6 @@ export const usePayment = () => { return false; } - // Payment succeeded setIsProcessing(false); return true; } catch (err) { diff --git a/src/hooks/useProductPage.ts b/src/hooks/useProductPage.ts index b885152..d042634 100644 --- a/src/hooks/useProductPage.ts +++ b/src/hooks/useProductPage.ts @@ -33,8 +33,6 @@ export const useProductPage = () => { (propertyName: string): string[] => { if (!allVariants.length) return []; - // Zwracamy WSZYSTKIE możliwe wartości dla danej właściwości ze WSZYSTKICH wariantów - // niezależnie od aktualnych wyborów, aby umożliwić przejście między wszystkimi wariantami const availableValues = new Set(); allVariants.forEach((variant) => { if (variant[propertyName]) { @@ -135,18 +133,13 @@ export const useProductPage = () => { [propertyName]: value, }; - // Najpierw próbujemy znaleźć dokładne dopasowanie let newVariantId = findVariantId(newSelections); - // Jeśli nie ma dokładnego dopasowania, szukamy wariantu który ma wybraną wartość dla zmienionej właściwości - // i zachowuje inne wybrane wartości (jeśli są dostępne) if (!newVariantId) { const matchingVariant = allVariants.find((variant) => { - // Sprawdzamy czy wariant ma wybraną wartość dla zmienionej właściwości if (variant[propertyName] !== value) { return false; } - // Sprawdzamy czy wariant ma wszystkie inne wybrane wartości (jeśli są) return Object.keys(newSelections).every( (key) => !newSelections[key] || variant[key] === newSelections[key], ); @@ -154,13 +147,11 @@ export const useProductPage = () => { newVariantId = matchingVariant?.variantId || null; } - // Jeśli nadal nie znaleźliśmy wariantu, szukamy dowolnego wariantu z wybraną wartością dla zmienionej właściwości if (!newVariantId) { const matchingVariant = allVariants.find((variant) => variant[propertyName] === value); newVariantId = matchingVariant?.variantId || null; } - // Jeśli nie znaleźliśmy wariantu, nie aktualizujemy stanu if (!newVariantId || newVariantId === variantId) { return; } @@ -176,8 +167,6 @@ export const useProductPage = () => { }); } - // Aktualizujemy wybrane właściwości na podstawie znalezionego wariantu - // To zapewnia, że wyświetlane wartości są zawsze zgodne z aktualnym wariantem if (newVariantData) { const updatedSelections: SelectedProperties = {}; selectablePropertyNames.forEach((propName) => { @@ -228,7 +217,6 @@ export const useProductPage = () => { if (!variant || variant.variantId !== variantId) { loadAllVariantDetails(variantId); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [variantId]); return { diff --git a/src/pages/CartPage.tsx b/src/pages/CartPage.tsx index 460dbfa..0e2a04a 100644 --- a/src/pages/CartPage.tsx +++ b/src/pages/CartPage.tsx @@ -274,7 +274,6 @@ const CartPage: React.FC = () => { const theme = useTheme(); const navigate = useNavigate(); - // Protection against empty cart const safeCartItems = Array.isArray(cartItems) ? cartItems : []; const subtotal = safeCartItems.reduce((sum, item) => { if (!item || typeof item.price !== "number" || typeof item.quantity !== "number") { @@ -286,7 +285,6 @@ const CartPage: React.FC = () => { const total = subtotal + shipping; const handleCheckout = async () => { - // Generate UUID for order const order = await createOrder({ items: safeCartItems.map((item) => ({ itemId: item.id, diff --git a/src/pages/Contact.tsx b/src/pages/Contact.tsx index 5eef451..4106df9 100644 --- a/src/pages/Contact.tsx +++ b/src/pages/Contact.tsx @@ -24,7 +24,6 @@ const Contact: React.FC = () => { try { setIsLoading(true); - // Check cache const cachedContact = sessionStorage.getItem(CACHE_KEY_CONTACT); let contactData: ContactPageContent | null = null; @@ -35,7 +34,6 @@ const Contact: React.FC = () => { } } - // If there's no cache or cache is old, load from API if (!contactData) { contactData = await fetchContactSettings(); sessionStorage.setItem( @@ -50,7 +48,6 @@ const Contact: React.FC = () => { setContactContent(contactData); } catch (error) { console.error("Failed to load contact content from CMS:", error); - // Fallback to default values } finally { setIsLoading(false); } diff --git a/src/pages/Faq.tsx b/src/pages/Faq.tsx index 1032fc7..02bbd2b 100644 --- a/src/pages/Faq.tsx +++ b/src/pages/Faq.tsx @@ -5,7 +5,6 @@ import MainLayout from "../components/layout/MainLayout"; import type { FaqPageContent } from "../types/cms"; import { Box, Container, Link, Typography, CircularProgress } from "@mui/material"; -// Default FAQ data (fallback) const defaultFaqData = [ { id: "faq1", @@ -51,7 +50,6 @@ const Faq: React.FC = () => { try { setIsLoading(true); - // Check cache const cachedFaq = sessionStorage.getItem(CACHE_KEY_FAQ); let faqData: FaqPageContent | null = null; @@ -62,7 +60,6 @@ const Faq: React.FC = () => { } } - // If there's no cache or cache is old, load from API if (!faqData) { faqData = await fetchFaqSettings(); sessionStorage.setItem( @@ -74,7 +71,6 @@ const Faq: React.FC = () => { setFaqContent(faqData); } catch (error) { console.error("Failed to load FAQ content from CMS:", error); - // Fallback to default values } finally { setIsLoading(false); } diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 6811741..87025c9 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -35,7 +35,6 @@ const Login: React.FC = () => { try { const loginData = await login(email, password); localStorage.setItem("token", loginData.token); - // Dispatch custom event to notify CartProvider about token change window.dispatchEvent(new Event("token-changed")); await refreshCurrentUser(); navigate("/"); diff --git a/src/pages/OrderConfirmationPage.tsx b/src/pages/OrderConfirmationPage.tsx index 4edbd31..79950ca 100644 --- a/src/pages/OrderConfirmationPage.tsx +++ b/src/pages/OrderConfirmationPage.tsx @@ -12,10 +12,8 @@ const OrderConfirmationPage: React.FC = () => { const navigate = useNavigate(); const theme = useTheme(); - // Get orderId from URL params const finalOrderId = orderId || "N/A"; - // Check if token is present (protection against forgery) if (!token) { return ( diff --git a/src/pages/PaymentPage.tsx b/src/pages/PaymentPage.tsx index ec0b01c..fac4920 100644 --- a/src/pages/PaymentPage.tsx +++ b/src/pages/PaymentPage.tsx @@ -30,16 +30,13 @@ const PaymentPage: React.FC = () => { clearPaymentError(); const success = await handlePayment(values); if (success) { - // Clear cart after successful payment await clearFullCart(); - // Redirect to order confirmation page with security token if (orderId) { const paymentLink = await getPaymentLink(orderId); await processPayment(paymentLink); const confirmationToken = crypto.randomUUID(); navigate(`/order-confirmation/${orderId}/${confirmationToken}`); } else { - // Fallback - if there's no orderId, redirect to home page navigate("/"); } } diff --git a/src/pages/ProductPage.tsx b/src/pages/ProductPage.tsx index 8a15a68..f7e340c 100644 --- a/src/pages/ProductPage.tsx +++ b/src/pages/ProductPage.tsx @@ -51,7 +51,6 @@ const ProductPage: React.FC = () => { getAvailableValues, } = useProductPage(); - // Get categoryId from URL params or from localStorage (if user came from category) const categoryIdFromUrl = searchParams.get("categoryId"); const [productCategoryId, setProductCategoryId] = useState( categoryIdFromUrl || @@ -104,7 +103,6 @@ const ProductPage: React.FC = () => { }) : ["https://via.placeholder.com/600x600?text=No+Image"]; - // Zawsze pokazuj REQUIRED i INFO, SELECTABLE tylko gdy showMoreParams jest true const displayedParams = showMoreParams ? [...selectableProperties, ...requiredProperties, ...infoProperties] : [...requiredProperties, ...infoProperties]; @@ -118,7 +116,6 @@ const ProductPage: React.FC = () => { setAddingToCart(true); try { - // productId in cart is actually variantId await addCartProduct(variant.variantId, quantity); await refetchCart(); } catch (error) { diff --git a/src/pages/admin/AddProductPage.tsx b/src/pages/admin/AddProductPage.tsx index 9411b3e..d8b2a02 100644 --- a/src/pages/admin/AddProductPage.tsx +++ b/src/pages/admin/AddProductPage.tsx @@ -206,7 +206,6 @@ const AddProductPage: React.FC = () => { setCreatingVariant(true); try { - // Automatycznie dodaj zdjęcia z textarea jeśli są tam jakieś URL-e let allImages = [...variantForm.variantImages]; if (imageInput.trim()) { const urlsFromInput = imageInput @@ -216,34 +215,29 @@ const AddProductPage: React.FC = () => { allImages = [...allImages, ...urlsFromInput]; } - // Filtrujemy puste stringi i upewniamy się że mamy tablicę stringów const images = allImages.filter((img) => img && img.trim().length > 0); - // Przygotuj standardowe właściwości const standardPropertyValues = Object.entries(propertyValues) .filter(([, value]) => value !== undefined && value !== "") .map(([propertyId, displayText]) => ({ propertyId, displayText })); - // Utwórz custom properties i pobierz ich ID const customPropertyValues: Array<{ propertyId: string; displayText: string }> = []; if (customProperties.length > 0 && productForm.categoryId) { for (const customProp of customProperties) { if (customProp.name.trim() && customProp.value.trim()) { try { - // Utwórz property w backendzie const propertyPayload: CreatePropertyGrpcRequestDTO = { categoryId: productForm.categoryId, name: customProp.name.trim(), - unit: "", // Dla INFO properties unit może być pusty + unit: "", dataType: "TEXT", role: "INFO", - defaultPropertyOptionValues: [], // Dla INFO properties pusta tablica + defaultPropertyOptionValues: [], }; const createdProperty = await createPropertyGrpc(propertyPayload); - // Dodaj do listy z właściwym ID customPropertyValues.push({ propertyId: createdProperty.id, displayText: customProp.value.trim(), @@ -275,7 +269,7 @@ const AddProductPage: React.FC = () => { price: variantForm.price, stockQuantity: variantForm.stockQuantity, description: variantForm.description, - variantImages: images, // Używamy przefiltrowanych zdjęć + variantImages: images, propertyValues: { ...propertyValues }, }; setVariantsCreated((prev) => [...prev, newVariant]); diff --git a/src/pages/admin/CategoryManagementPage.tsx b/src/pages/admin/CategoryManagementPage.tsx index ad6d16b..653d0de 100644 --- a/src/pages/admin/CategoryManagementPage.tsx +++ b/src/pages/admin/CategoryManagementPage.tsx @@ -107,10 +107,8 @@ const CategoryManagementPage: React.FC = () => { const result = await createCategory(requestData); - // Set newly added category ID for highlighting setNewlyAddedCategoryId(result.id); - // Clear highlight after 6 seconds (3 animations * 2 seconds) setTimeout(() => { setNewlyAddedCategoryId(null); }, 6000); @@ -130,7 +128,6 @@ const CategoryManagementPage: React.FC = () => { handleCloseDeleteDialog(); } catch (err) { console.error("Error deleting category:", err); - // Note: Backend endpoint may not be implemented yet alert("Error: Category deletion endpoint may not be implemented yet on the backend."); throw err; } diff --git a/src/pages/admin/ContactPageEditor.tsx b/src/pages/admin/ContactPageEditor.tsx index b193fce..870b8ed 100644 --- a/src/pages/admin/ContactPageEditor.tsx +++ b/src/pages/admin/ContactPageEditor.tsx @@ -9,7 +9,6 @@ import EmailIcon from "@mui/icons-material/Email"; import PhoneIcon from "@mui/icons-material/Phone"; import { Container, Typography, Grid, Box, Link, Alert, Snackbar } from "@mui/material"; -// Mock initial data const defaultContactSettings = { pageTitle: "Contact", pageSubtitle: "Need help? See frequently asked questions", @@ -27,7 +26,6 @@ const ContactPageEditor: React.FC = () => { const [showError, setShowError] = useState(false); const [isInitialized, setIsInitialized] = useState(false); - // Initialization - fetch data from API useEffect(() => { const initializeData = async () => { if (!isInitialized && !settings?.contactPage) { @@ -112,7 +110,6 @@ const ContactPageEditor: React.FC = () => { if (!settings || !settings.contactPage) return; setIsSaving(true); try { - // Konwertuj na ContactPageContent const contactSettingsData = { pageTitle: settings.contactPage.pageTitle, pageSubtitle: settings.contactPage.pageSubtitle, @@ -123,10 +120,8 @@ const ContactPageEditor: React.FC = () => { emailDescription: settings.contactPage.emailDescription, }; - // Save using the new endpoint await saveContactSettings(contactSettingsData); - // Clear Contact cache so updated data is visible when returning to Contact page sessionStorage.removeItem("contact_cache"); setDirty(false); diff --git a/src/pages/admin/FaqPageEditor.tsx b/src/pages/admin/FaqPageEditor.tsx index bfea8c6..6e55358 100644 --- a/src/pages/admin/FaqPageEditor.tsx +++ b/src/pages/admin/FaqPageEditor.tsx @@ -58,7 +58,6 @@ const FaqPageEditor: React.FC = () => { const [showError, setShowError] = useState(false); const [isInitialized, setIsInitialized] = useState(false); - // Initialization - fetch data from API useEffect(() => { const initializeData = async () => { if (!isInitialized && !settings?.faqPage) { @@ -156,17 +155,14 @@ const FaqPageEditor: React.FC = () => { if (!settings || !settings.faqPage) return; setIsSaving(true); try { - // Konwertuj na FaqPageContent const faqSettings = { pageTitle: settings.faqPage.pageTitle, pageSubtitle: settings.faqPage.pageSubtitle, faqItems: settings.faqPage.faqItems, }; - // Save using the new endpoint await saveFaqSettings(faqSettings); - // Clear FAQ cache so updated data is visible when returning to FAQ page sessionStorage.removeItem("faq_cache"); setDirty(false); @@ -335,7 +331,6 @@ const FaqPageEditor: React.FC = () => { ))} - {/* Button for adding new FAQ */} void; @@ -118,7 +117,6 @@ const SortableFeatureItem: React.FC = ({ }, }} > - {/* Drag Handle */} = ({ - {/* Delete Button */} = ({ ); }; -// Sortable Category Item Component interface SortableCategoryItemProps { category: CategoryFromAPI; index: number; @@ -235,7 +231,6 @@ const SortableCategoryItem: React.FC = ({ }, }} > - {/* Remove Button */} = ({ - {/* Category Header with Color */} = ({ /> - {/* Category Details */} = ({ ); }; -// Mock initial data const defaultSettings = { hero: { title: "Welcome to E-COMMERCE", @@ -453,7 +445,6 @@ const HomePageEditor: React.FC = () => { const [categoryDialogOpen, setCategoryDialogOpen] = useState(false); const [isInitialized, setIsInitialized] = useState(false); - // Sensors for drag and drop const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { @@ -465,13 +456,11 @@ const HomePageEditor: React.FC = () => { }), ); - // Initialization - fetch data from API or use defaults useEffect(() => { const initializeData = async () => { if (!isInitialized && !settings) { try { const data = await fetchHomeSettings(); - // Konwertuj HomePageContent na GlobalSettings setSettings({ ...defaultSettings, hero: data.hero, @@ -524,7 +513,6 @@ const HomePageEditor: React.FC = () => { if (!settings) return; setIsSaving(true); try { - // Konwertuj GlobalSettings na HomePageContent const homeSettings = { hero: settings.hero, features: settings.features, @@ -536,14 +524,11 @@ const HomePageEditor: React.FC = () => { selectedCategoryIds: selectedCategoryIds, }; - // Save using the new endpoint await saveHomeSettings(homeSettings); - // Clear cache so updated data is visible when returning to home page sessionStorage.removeItem("homepage_cache"); sessionStorage.removeItem("homepage_categories"); - // Update local state const updatedSettings = { ...settings, selectedCategoryIds: selectedCategoryIds, @@ -594,7 +579,6 @@ const HomePageEditor: React.FC = () => { return colors[index % colors.length]; }; - // Handler for dragging features const handleFeaturesDragEnd = (event: DragEndEvent) => { if (!settings) return; @@ -610,7 +594,6 @@ const HomePageEditor: React.FC = () => { } }; - // Handler for dragging categories const handleCategoriesDragEnd = (event: DragEndEvent) => { const { active, over } = event; @@ -630,7 +613,6 @@ const HomePageEditor: React.FC = () => { <> - {/* Hero Section */} @@ -673,7 +655,6 @@ const HomePageEditor: React.FC = () => { - {/* Features */} { - {/* Categories */} { - {/* Category Selection Section */} Select categories from the system to be displayed on the home page @@ -804,7 +783,6 @@ const HomePageEditor: React.FC = () => { > - {/* Selected Category Tiles */} {getSelectedCategories().map((category, index) => ( { /> ))} - {/* Add Category Button */} {getAvailableCategoriesToAdd().length > 0 && ( { - {/* Footer - edytowalna stopka */} { > - {/* About Section */} { /> - {/* Social Media Icons */} { - {/* Spacer - dwie puste kolumny */} - {/* Customer Service */} Customer Service @@ -1088,7 +1060,6 @@ const HomePageEditor: React.FC = () => { - {/* Copyright */} { - {/* Category Selection Dialog */} setCategoryDialogOpen(false)} From a8c14acf4fb2d19ef511980ba6296ee9ab3e4904 Mon Sep 17 00:00:00 2001 From: arcadio77 <66469918+arcadio77@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:28:06 +0100 Subject: [PATCH 2/2] fix 2 --- src/api/order-service.ts | 8 +- src/components/common/Header.tsx | 1 + src/components/orders/OrderRow.tsx | 8 +- src/contexts/CartProvider.tsx | 2 +- src/hooks/useCheckout.ts | 1 + src/hooks/useProductPage.ts | 9 +- src/pages/CartPage.tsx | 4 +- src/pages/PaymentPage.tsx | 2 +- .../admin/analytics/SalesStatisticsPage.tsx | 86 ++++++++++--------- src/types/orders.ts | 1 - 10 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/api/order-service.ts b/src/api/order-service.ts index 0f6c9b9..b2603c3 100644 --- a/src/api/order-service.ts +++ b/src/api/order-service.ts @@ -1,4 +1,8 @@ -import type { OrderCreateRequest, OrderCreateResponse, OrderDetailsResponse } from "../types/orders"; +import type { + OrderCreateRequest, + OrderCreateResponse, + OrderDetailsResponse, +} from "../types/orders"; import { API_BASE_URL, apiCall } from "./utils"; export const fetchUserOrders = async (): Promise => { @@ -80,4 +84,4 @@ export const createOrder = async (order: OrderCreateRequest): Promise = ({ minimalist }) => { }); } } catch { + // Silently ignore prefetch errors } }; diff --git a/src/components/orders/OrderRow.tsx b/src/components/orders/OrderRow.tsx index f33ccbd..8cc1210 100644 --- a/src/components/orders/OrderRow.tsx +++ b/src/components/orders/OrderRow.tsx @@ -1,9 +1,9 @@ import { useState, useEffect } from "react"; +import { getAllVariantDetails } from "../../api/product-service"; import { type OrderDetailsResponse, type OrderItemDetails } from "../../types/orders.ts"; import { getStatusColor, getStatusLabel } from "../../types/orders.ts"; -import { formatDate } from "../../utils/string.ts"; -import { getAllVariantDetails } from "../../api/product-service"; import type { GetVariantResponseDTO } from "../../types/products"; +import { formatDate } from "../../utils/string.ts"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; import { @@ -141,7 +141,9 @@ const OrderItemRow: React.FC = ({ item, index }) => { )} + {productName} diff --git a/src/contexts/CartProvider.tsx b/src/contexts/CartProvider.tsx index 2fa99ca..05c41a1 100644 --- a/src/contexts/CartProvider.tsx +++ b/src/contexts/CartProvider.tsx @@ -156,7 +156,7 @@ export default function CartProvider({ children }: { children: ReactNode }) { useEffect(() => { refetchCart(); - }, []); + }, [refetchCart]); useEffect(() => { const handleStorageChange = (e: StorageEvent) => { diff --git a/src/hooks/useCheckout.ts b/src/hooks/useCheckout.ts index d434ff9..ea73a85 100644 --- a/src/hooks/useCheckout.ts +++ b/src/hooks/useCheckout.ts @@ -137,6 +137,7 @@ export const useCheckout = (initialOrderId?: string) => { return; } } catch { + // Silently ignore parsing errors } } diff --git a/src/hooks/useProductPage.ts b/src/hooks/useProductPage.ts index d042634..e7a3e53 100644 --- a/src/hooks/useProductPage.ts +++ b/src/hooks/useProductPage.ts @@ -217,7 +217,14 @@ export const useProductPage = () => { if (!variant || variant.variantId !== variantId) { loadAllVariantDetails(variantId); } - }, [variantId]); + }, [ + variantId, + allVariants, + loadAllVariantDetails, + loadVariantDetails, + loadVariantProperties, + variant, + ]); return { variant, diff --git a/src/pages/CartPage.tsx b/src/pages/CartPage.tsx index 0e2a04a..ef74d72 100644 --- a/src/pages/CartPage.tsx +++ b/src/pages/CartPage.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from "react"; +import { createOrder } from "../api/order-service.ts"; import { getVariantDetails } from "../api/product-service"; import Breadcrumbs from "../components/common/Breadcrumbs.tsx"; import MainLayout from "../components/layout/MainLayout.tsx"; @@ -27,7 +28,6 @@ import { useTheme, } from "@mui/material"; import { useNavigate } from "react-router-dom"; -import { createOrder } from "../api/order-service.ts"; const SHIPPING_COST = 19.99; const FREE_SHIPPING_THRESHOLD = 500; @@ -297,7 +297,7 @@ const CartPage: React.FC = () => { isReturnable: true, })), }); - const orderId = order.orderId + const orderId = order.orderId; navigate(`/order/${orderId}`); }; diff --git a/src/pages/PaymentPage.tsx b/src/pages/PaymentPage.tsx index fac4920..ade61b9 100644 --- a/src/pages/PaymentPage.tsx +++ b/src/pages/PaymentPage.tsx @@ -1,4 +1,5 @@ import React, { useRef, useState } from "react"; +import { getPaymentLink, processPayment } from "../api/payment-service.ts"; import Breadcrumbs from "../components/common/Breadcrumbs.tsx"; import CardForm, { type CardFormRef } from "../components/forms/CardForm.tsx"; import MainLayout from "../components/layout/MainLayout.tsx"; @@ -8,7 +9,6 @@ import PaymentSummary from "./payment/PaymentSummary.tsx"; import CreditCardIcon from "@mui/icons-material/CreditCard"; import { Box, Typography, Container, Grid, Alert, Card, Button } from "@mui/material"; import { useNavigate, useParams } from "react-router-dom"; -import { getPaymentLink, processPayment } from "../api/payment-service.ts"; const PaymentPage: React.FC = () => { const navigate = useNavigate(); diff --git a/src/pages/admin/analytics/SalesStatisticsPage.tsx b/src/pages/admin/analytics/SalesStatisticsPage.tsx index 482b680..5e71c40 100644 --- a/src/pages/admin/analytics/SalesStatisticsPage.tsx +++ b/src/pages/admin/analytics/SalesStatisticsPage.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useCallback } from "react"; import { getVariantSalesOverTime, getVariantStockOverTime } from "../../../api/statistics-service"; import DateRangeSelector from "../../../components/analytics/DateRangeSelector"; import SalesChart from "../../../components/analytics/SalesChart"; @@ -36,6 +36,50 @@ const SalesStatisticsPage: React.FC = () => { return { fromDate, toDate: today }; }); + const loadSalesData = useCallback( + async (variantId: string) => { + setSalesLoading(true); + setError(null); + try { + const data = await getVariantSalesOverTime(variantId, { + fromDate: dateRange.fromDate?.toISOString().split("T")[0], + toDate: dateRange.toDate?.toISOString().split("T")[0], + trendDays: 30, + }); + + setSalesData(data); + } catch (err) { + console.error("Error loading sales data:", err); + setError("Failed to load sales data. Please check the server connection."); + } finally { + setSalesLoading(false); + } + }, + [dateRange], + ); + + const loadStockData = useCallback( + async (variantId: string) => { + setStockLoading(true); + setError(null); + try { + const data = await getVariantStockOverTime(variantId, { + fromDate: dateRange.fromDate?.toISOString().split("T")[0], + toDate: dateRange.toDate?.toISOString().split("T")[0], + trendDays: 30, + }); + + setStockData(data); + } catch (err) { + console.error("Error loading stock data:", err); + setError("Failed to load stock data. Please check the server connection."); + } finally { + setStockLoading(false); + } + }, + [dateRange], + ); + // Load data when variant or date range changes useEffect(() => { if (selectedVariant) { @@ -48,45 +92,7 @@ const SalesStatisticsPage: React.FC = () => { setSalesData(null); setStockData(null); } - }, [selectedVariant, dateRange, activeTab]); - - const loadSalesData = async (variantId: string) => { - setSalesLoading(true); - setError(null); - try { - const data = await getVariantSalesOverTime(variantId, { - fromDate: dateRange.fromDate?.toISOString().split("T")[0], - toDate: dateRange.toDate?.toISOString().split("T")[0], - trendDays: 30, - }); - - setSalesData(data); - } catch (err) { - console.error("Error loading sales data:", err); - setError("Failed to load sales data. Please check the server connection."); - } finally { - setSalesLoading(false); - } - }; - - const loadStockData = async (variantId: string) => { - setStockLoading(true); - setError(null); - try { - const data = await getVariantStockOverTime(variantId, { - fromDate: dateRange.fromDate?.toISOString().split("T")[0], - toDate: dateRange.toDate?.toISOString().split("T")[0], - trendDays: 30, - }); - - setStockData(data); - } catch (err) { - console.error("Error loading stock data:", err); - setError("Failed to load stock data. Please check the server connection."); - } finally { - setStockLoading(false); - } - }; + }, [selectedVariant, dateRange, activeTab, loadSalesData, loadStockData]); const handleVariantSelect = (variant: VariantInfoDTO | null) => { setSelectedVariant(variant); diff --git a/src/types/orders.ts b/src/types/orders.ts index c9c3335..04fbdbe 100644 --- a/src/types/orders.ts +++ b/src/types/orders.ts @@ -44,7 +44,6 @@ export interface OrderCreateResponse { failedVariants: FailedReservationVariantDto[]; } - export const getStatusLabel = (status: string): string => { return STATUS_LABELS[status as OrderStatus] || status; };