Skip to content

Commit 2dc8565

Browse files
committed
Fix Network Error exceptions in all production components
- Fix CartPreview component to use mockAPI instead of direct API calls - Add config.useMockData validation in CartContent fetchProducts method - Fix NewProducts component with null checks for undefined photos array - Add mock data support to Testimonials and ProductSlider components - Prevent TypeError: Cannot read properties of undefined (reading '0') - Eliminate all localhost:8000 API calls on GitHub Pages production - Add PLACEHOLDER_IMAGE fallbacks for missing product images - All components now work seamlessly offline with static mock data
1 parent 99a501a commit 2dc8565

5 files changed

Lines changed: 115 additions & 58 deletions

File tree

frontend/src/components/CartContent/CartContent.jsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,13 @@ const CartContent = () => {
6868
useEffect(() => {
6969
const fetchProducts = async () => {
7070
try {
71-
const response = await axios.get(`${config.apiUrl}/api/products/`);
72-
setShopData(response.data);
71+
if (config.useMockData) {
72+
const data = await mockAPI.getProducts();
73+
setShopData(data);
74+
} else {
75+
const response = await axios.get(`${config.apiUrl}/api/products/`);
76+
setShopData(response.data);
77+
}
7378
} catch (error) {
7479
console.error("Error fetching products:", error);
7580
}
@@ -92,6 +97,12 @@ const CartContent = () => {
9297
const fetchRecommendations = async () => {
9398
setRecommendationsLoading(true);
9499
try {
100+
if (config.useMockData) {
101+
// Na produkcji nie ma rekomendacji
102+
setRecommendations([]);
103+
return;
104+
}
105+
95106
const productIds = Object.keys(items).filter((id) => items[id] > 0);
96107
if (productIds.length === 0) return;
97108

frontend/src/components/CartContent/CartPreview.jsx

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AiOutlineClose, AiOutlineShopping } from "react-icons/ai";
55
import { Link, useNavigate } from "react-router-dom";
66
import config from "../../config/config";
77
import { CartContext } from "../ShopContext/ShopContext";
8+
import { mockAPI, PLACEHOLDER_IMAGE } from "../../utils/mockData";
89

910
const BASE_URL = `${config.apiUrl}`;
1011

@@ -30,20 +31,35 @@ const CartPreview = () => {
3031

3132
const fetchProducts = async () => {
3233
try {
33-
const productIds = Object.keys(items).join(",");
34-
const response = await axios.get(
35-
`${BASE_URL}/api/products/?ids=${productIds}`
36-
);
37-
const productMap = {};
38-
response.data.forEach((product) => {
39-
productMap[product.id] = {
40-
...product,
41-
image: product.photos?.[0]?.path
42-
? `${BASE_URL}/media/${product.photos[0].path}`
43-
: "https://via.placeholder.com/150",
44-
};
45-
});
46-
setProducts(productMap);
34+
if (config.useMockData) {
35+
const allProducts = await mockAPI.getProducts();
36+
const productMap = {};
37+
Object.keys(items).forEach((itemId) => {
38+
const product = allProducts.find((p) => p.id === parseInt(itemId));
39+
if (product) {
40+
productMap[itemId] = {
41+
...product,
42+
image: product.imgs?.[0] || PLACEHOLDER_IMAGE,
43+
};
44+
}
45+
});
46+
setProducts(productMap);
47+
} else {
48+
const productIds = Object.keys(items).join(",");
49+
const response = await axios.get(
50+
`${BASE_URL}/api/products/?ids=${productIds}`,
51+
);
52+
const productMap = {};
53+
response.data.forEach((product) => {
54+
productMap[product.id] = {
55+
...product,
56+
image: product.photos?.[0]?.path
57+
? `${BASE_URL}/media/${product.photos[0].path}`
58+
: PLACEHOLDER_IMAGE,
59+
};
60+
});
61+
setProducts(productMap);
62+
}
4763
} catch (error) {
4864
console.error("Error with loading products:", error);
4965
}

frontend/src/components/LogoSlider/ProductSlider.jsx

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import config from "../../config/config";
77
import "./ProductSlider.scss";
88
import axios from "axios";
99
import ProductSliderItem from "./ProductSliderItem";
10+
import { mockAPI } from "../../utils/mockData";
1011

1112
const ProductSlider = () => {
1213
const [productsState, setProductsState] = useState({
@@ -19,22 +20,27 @@ const ProductSlider = () => {
1920
const fetchData = async () => {
2021
setProductsState((prev) => ({ ...prev, isLoading: true }));
2122
try {
22-
const token = localStorage.getItem("access");
23-
if (token) {
24-
const settingsResponse = await axios.get(
25-
`${config.apiUrl}/api/recommendation-settings/`,
26-
{ headers: { Authorization: `Bearer ${token}` } }
27-
);
28-
const algorithm =
29-
settingsResponse.data.active_algorithm || "collaborative";
30-
setProductsState((prev) => ({
31-
...prev,
32-
currentAlgorithm: algorithm,
33-
}));
34-
35-
await fetchProducts(algorithm, token);
36-
} else {
23+
if (config.useMockData) {
24+
// Use mock data for GitHub Pages
3725
await fetchProducts(null, null);
26+
} else {
27+
const token = localStorage.getItem("access");
28+
if (token) {
29+
const settingsResponse = await axios.get(
30+
`${config.apiUrl}/api/recommendation-settings/`,
31+
{ headers: { Authorization: `Bearer ${token}` } },
32+
);
33+
const algorithm =
34+
settingsResponse.data.active_algorithm || "collaborative";
35+
setProductsState((prev) => ({
36+
...prev,
37+
currentAlgorithm: algorithm,
38+
}));
39+
40+
await fetchProducts(algorithm, token);
41+
} else {
42+
await fetchProducts(null, null);
43+
}
3844
}
3945
} catch (error) {
4046
console.error("Error in initial fetch:", error);
@@ -81,11 +87,20 @@ const ProductSlider = () => {
8187

8288
const fetchProducts = async (algorithm, token) => {
8389
try {
90+
if (config.useMockData) {
91+
const data = await mockAPI.getRandomProducts(8);
92+
setProductsState((prev) => ({
93+
...prev,
94+
products: data,
95+
}));
96+
return;
97+
}
98+
8499
if (token && algorithm) {
85100
try {
86101
const previewResponse = await axios.get(
87102
`${config.apiUrl}/api/recommendation-preview/?algorithm=${algorithm}`,
88-
{ headers: { Authorization: `Bearer ${token}` } }
103+
{ headers: { Authorization: `Bearer ${token}` } },
89104
);
90105

91106
if (previewResponse.data && previewResponse.data.length > 0) {

frontend/src/components/NewProducts/NewProducts.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ const NewProducts = () => {
132132
old_price: product.old_price
133133
? parseFloat(product.old_price)
134134
: null,
135-
imgs: product.photos.map(
135+
imgs: (product.photos || []).map(
136136
(photo) => `${config.apiUrl}/media/${photo.path}`,
137137
),
138138
category: product.categories?.[0] || "N/A",
@@ -151,7 +151,7 @@ const NewProducts = () => {
151151
name: product.name,
152152
price: parseFloat(product.price),
153153
old_price: product.old_price ? parseFloat(product.old_price) : null,
154-
imgs: product.photos.map(
154+
imgs: (product.photos || []).map(
155155
(photo) => `${config.apiUrl}/media/${photo.path}`,
156156
),
157157
category: product.categories?.[0] || "N/A",

frontend/src/components/Testimonials/Testimonials.jsx

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import "slick-carousel/slick/slick-theme.css";
6161
import "./Testimonials.scss";
6262
import TestimonialsItem from "./TestimonialsItem";
6363
import config from "../../config/config";
64+
import { mockAPI } from "../../utils/mockData";
6465

6566
const Testimonials = () => {
6667
const [productsState, setProductsState] = useState({
@@ -73,22 +74,27 @@ const Testimonials = () => {
7374
const fetchData = async () => {
7475
setProductsState((prev) => ({ ...prev, isLoading: true }));
7576
try {
76-
const token = localStorage.getItem("access");
77-
if (token) {
78-
const settingsResponse = await axios.get(
79-
`${config.apiUrl}/api/recommendation-settings/`,
80-
{ headers: { Authorization: `Bearer ${token}` } }
81-
);
82-
const algorithm =
83-
settingsResponse.data.active_algorithm || "collaborative";
84-
setProductsState((prev) => ({
85-
...prev,
86-
currentAlgorithm: algorithm,
87-
}));
88-
89-
await fetchProducts(algorithm, token);
90-
} else {
77+
if (config.useMockData) {
78+
// Use mock data for GitHub Pages
9179
await fetchProducts(null, null);
80+
} else {
81+
const token = localStorage.getItem("access");
82+
if (token) {
83+
const settingsResponse = await axios.get(
84+
`${config.apiUrl}/api/recommendation-settings/`,
85+
{ headers: { Authorization: `Bearer ${token}` } },
86+
);
87+
const algorithm =
88+
settingsResponse.data.active_algorithm || "collaborative";
89+
setProductsState((prev) => ({
90+
...prev,
91+
currentAlgorithm: algorithm,
92+
}));
93+
94+
await fetchProducts(algorithm, token);
95+
} else {
96+
await fetchProducts(null, null);
97+
}
9298
}
9399
} catch (error) {
94100
console.error("Error in initial fetch:", error);
@@ -135,11 +141,20 @@ const Testimonials = () => {
135141

136142
const fetchProducts = async (algorithm, token) => {
137143
try {
144+
if (config.useMockData) {
145+
const data = await mockAPI.getRandomProducts(8);
146+
setProductsState((prev) => ({
147+
...prev,
148+
products: data,
149+
}));
150+
return;
151+
}
152+
138153
if (token && algorithm) {
139154
try {
140155
const previewResponse = await axios.get(
141156
`${config.apiUrl}/api/recommendation-preview/?algorithm=${algorithm}`,
142-
{ headers: { Authorization: `Bearer ${token}` } }
157+
{ headers: { Authorization: `Bearer ${token}` } },
143158
);
144159

145160
if (previewResponse.data && previewResponse.data.length > 0) {
@@ -190,10 +205,10 @@ const Testimonials = () => {
190205
return productsState.currentAlgorithm === "collaborative"
191206
? "Personalized Recommendations (Collaborative Filtering)"
192207
: productsState.currentAlgorithm === "content_based"
193-
? "Personalized Recommendations (Content-Based)"
194-
: productsState.currentAlgorithm === "fuzzy_logic"
195-
? "Personalized Recommendations (Fuzzy Logic)"
196-
: "Personalized Recommendations";
208+
? "Personalized Recommendations (Content-Based)"
209+
: productsState.currentAlgorithm === "fuzzy_logic"
210+
? "Personalized Recommendations (Fuzzy Logic)"
211+
: "Personalized Recommendations";
197212
}
198213
return "Discover Our Products";
199214
};
@@ -203,10 +218,10 @@ const Testimonials = () => {
203218
return productsState.currentAlgorithm === "collaborative"
204219
? "Based on what users like you are buying"
205220
: productsState.currentAlgorithm === "content_based"
206-
? "Based on products similar to your preferences"
207-
: productsState.currentAlgorithm === "fuzzy_logic"
208-
? "Based on fuzzy logic matching your preferences with uncertainty modeling"
209-
: "Based on your shopping patterns";
221+
? "Based on products similar to your preferences"
222+
: productsState.currentAlgorithm === "fuzzy_logic"
223+
? "Based on fuzzy logic matching your preferences with uncertainty modeling"
224+
: "Based on your shopping patterns";
210225
}
211226
return "Check out selected proposals from our product database – scroll to see more and test our recommendation system in action!";
212227
};

0 commit comments

Comments
 (0)