Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 126 additions & 6 deletions src/api/product-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,34 @@ import type {
GetProductsRequestDTO,
GetProductsResponseDTO,
GetVariantResponseDTO,
ProductCreateRequestDTO,
ProductCreateResponseDTO,
ProductCreateRequestDTO,
VariantCreateGrpcRequestDTO,
VariantCreateResponseDTO,
CategoryPropertyGroupResponse,
VariantPropertyResponseDTO,
} from "../types/products";
import { apiCall } from "./utils";
import { API_BASE_URL, apiCall } from "./utils";

const PRODUCT_SERVICE_URL = "http://localhost:8400";
const PRODUCT_API = `${PRODUCT_SERVICE_URL}/api/products`;
const VARIANT_API = `${PRODUCT_SERVICE_URL}/api/variant`;
const CATEGORY_API = `${PRODUCT_SERVICE_URL}/api/categories`;
const PROPERTIES_API = `${PRODUCT_SERVICE_URL}/api/properties`;
const PRODUCT_GRPC_API = `${API_BASE_URL}/api/products/grpc`;
const VARIANT_GRPC_API = `${API_BASE_URL}/api/variants/grpc`;

export const createProduct = async (
productData: ProductCreateRequestDTO,
): Promise<ProductCreateResponseDTO> => {
const jwtToken = localStorage.getItem("token");
try {
const response = await apiCall(PRODUCT_API, {
const response = await apiCall(PRODUCT_GRPC_API, {
method: "POST",
headers: {
Authorization: `Bearer ${jwtToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(productData),
});

Expand Down Expand Up @@ -217,6 +228,8 @@ export const searchProducts = async (
throw new Error(`Failed to search products: ${response.status} ${response.statusText}`);
}

console.log(response.json());

return await response.json();
} catch (error) {
console.error("API Error searching products:", error);
Expand All @@ -236,7 +249,11 @@ export const getAllVariantDetails = async (variantId: string): Promise<GetVarian
);
}

return await response.json();
const res = await response.json();

console.log("bajojajo222", res);

return res;
} catch (error) {
console.error("API Error getting all variant details:", error);
throw error;
Expand All @@ -253,7 +270,11 @@ export const getVariantDetails = async (variantId: string): Promise<GetVariantRe
throw new Error(`Failed to get variant details: ${response.status} ${response.statusText}`);
}

return await response.json();
const res = await response.json();

console.log("bajojajo222", res);

return res;
} catch (error) {
console.error("API Error getting variant details:", error);
throw error;
Expand All @@ -274,9 +295,108 @@ export const getVariantProperties = async (
);
}

return await response.json();
const res = await response.json();

console.log("bajojajo", res);

return res;
} catch (error) {
console.error("API Error getting variant properties:", error);
throw error;
}
};

export const getCategoryProperties = async (
categoryId: string,
): Promise<CategoryPropertyGroupResponse> => {
try {
const url = new URL(PROPERTIES_API);
url.searchParams.set("categoryId", categoryId);

const response = await apiCall(url.toString(), {
method: "GET",
});

if (!response.ok) {
throw new Error(
`Failed to get properties for category: ${response.status} ${response.statusText}`,
);
}

return await response.json();
} catch (error) {
console.error("API Error fetching category properties:", error);
throw error;
}
};

export interface CreatePropertyGrpcRequestDTO {
categoryId: string;
name: string;
unit: string;
dataType: string;
role: "SELECTABLE" | "REQUIRED" | "INFO";
defaultPropertyOptionValues: string[];
}

export interface CreatePropertyGrpcResponseDTO {
id: string;
}

const PROPERTIES_GRPC_API = `${API_BASE_URL}/api/properties/grpc`;

export const createPropertyGrpc = async (
propertyData: CreatePropertyGrpcRequestDTO,
): Promise<CreatePropertyGrpcResponseDTO> => {
const jwtToken = localStorage.getItem("token");

try {
const response = await apiCall(PROPERTIES_GRPC_API, {
method: "POST",
headers: {
Authorization: `Bearer ${jwtToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(propertyData),
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(
`Failed to create property: ${response.status} ${response.statusText} - ${errorText}`,
);
}

return await response.json();
} catch (error) {
console.error("API Error creating property:", error);
throw error;
}
};

export const createVariantGrpc = async (
variantData: VariantCreateGrpcRequestDTO,
): Promise<VariantCreateResponseDTO> => {
const jwtToken = localStorage.getItem("token");
console.log("createVariant", variantData);

try {
const response = await apiCall(VARIANT_GRPC_API, {
method: "POST",
headers: {
Authorization: `Bearer ${jwtToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(variantData),
});

if (!response.ok) {
throw new Error(`Failed to create variant: ${response.status} ${response.statusText}`);
}

return await response.json();
} catch (error) {
console.error("API Error creating variant:", error);
throw error;
}
};
9 changes: 8 additions & 1 deletion src/api/role-service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { Role } from "../types/users.ts";
import { API_BASE_URL, apiCall, jwtToken } from "./utils.ts";
import { API_BASE_URL, apiCall } from "./utils.ts";

export const fetchRoles = async (): Promise<Role[]> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand All @@ -27,6 +28,7 @@ export const fetchRoles = async (): Promise<Role[]> => {
};

export const addRole = async (role: Role): Promise<void> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand All @@ -51,6 +53,7 @@ export const addRole = async (role: Role): Promise<void> => {
};

export const updateRole = async (role: Role): Promise<void> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand All @@ -75,6 +78,7 @@ export const updateRole = async (role: Role): Promise<void> => {
};

export const deleteRole = async (roleName: string): Promise<void> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand All @@ -98,6 +102,7 @@ export const deleteRole = async (roleName: string): Promise<void> => {
};

export const addUsersToRole = async (roleName: string, userIds: string[]): Promise<void> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand All @@ -123,6 +128,7 @@ export const addUsersToRole = async (roleName: string, userIds: string[]): Promi
};

export const deleteUsersFromRole = async (roleName: string, userIds: string[]): Promise<void> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand Down Expand Up @@ -150,6 +156,7 @@ export const deleteUsersFromRole = async (roleName: string, userIds: string[]):
};

export const fetchRolesPermissions = async (): Promise<string[]> => {
const jwtToken = localStorage.getItem("token");
if (!jwtToken) {
throw new Error("Authorization token not found. Please log in.");
}
Expand Down
2 changes: 0 additions & 2 deletions src/api/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const API_BASE_URL = import.meta.env.VITE_API_URL || "http://localhost:8600";

export const jwtToken = localStorage.getItem("token");

const apiCall = async (url: string, options: RequestInit = {}) => {
const defaultOptions: RequestInit = {
credentials: "include",
Expand Down
21 changes: 0 additions & 21 deletions src/components/forms/CreateProductForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const initialProductValues: ProductFormValues = {
approximatePrice: 0,
deliveryPrice: 0,
description: "",
info: {},
};

const productValidationSchema = Yup.object({
Expand Down Expand Up @@ -122,26 +121,6 @@ const CreateProductForm: React.FC<CreateProductFormProps> = ({ onSubmit }) => {
placeholder="Detailed product description"
/>
</Grid>
<Grid size={{ xs: 12 }}>
<Typography variant="body2" sx={{ mb: 1, fontWeight: 500 }}>
Dodatkowe Info (JSON)
</Typography>
<TextField
fullWidth
name="info"
multiline
rows={4}
placeholder='np. {"manufacturer": "XYZ", "weight_g": 500}'
/>
<Typography
variant="caption"
display="block"
color="text.secondary"
sx={{ mt: 0.5 }}
>
Enter additional product attributes as a valid JSON object.
</Typography>
</Grid>

<Grid size={{ xs: 12 }}>
<Box sx={{ mt: 1, display: "flex", justifyContent: "flex-end" }}>
Expand Down
60 changes: 40 additions & 20 deletions src/hooks/useProductPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,18 @@ export const useProductPage = () => {
(propertyName: string): string[] => {
if (!allVariants.length) return [];

const currentSelections = { ...selectedProperties };
delete currentSelections[propertyName];

// 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<string>();
allVariants.forEach((variant) => {
const matchesCurrentSelection = Object.keys(currentSelections).every(
(key) => variant[key] === currentSelections[key],
);

if (matchesCurrentSelection && variant[propertyName]) {
if (variant[propertyName]) {
availableValues.add(variant[propertyName]);
}
});

return Array.from(availableValues);
},
[allVariants, selectedProperties],
[allVariants],
);

const findVariantId = useCallback(
Expand Down Expand Up @@ -140,19 +135,33 @@ export const useProductPage = () => {
[propertyName]: value,
};

selectablePropertyNames.forEach((propName) => {
if (propName !== propertyName) {
const availableValues = getAvailableValues(propName);
if (availableValues.length > 0 && !availableValues.includes(newSelections[propName])) {
delete newSelections[propName];
// 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],
);
});
newVariantId = matchingVariant?.variantId || null;
}

setSelectedProperties(newSelections);
// 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;
}

const newVariantId = findVariantId(newSelections);
if (!(newVariantId && newVariantId !== variantId)) {
// Jeśli nie znaleźliśmy wariantu, nie aktualizujemy stanu
if (!newVariantId || newVariantId === variantId) {
return;
}

Expand All @@ -167,6 +176,18 @@ 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) => {
if (newVariantData[propName]) {
updatedSelections[propName] = newVariantData[propName];
}
});
setSelectedProperties(updatedSelections);
}

navigate(`/product/${newVariantId}`, { replace: true, preventScrollReset: true });

loadVariantDetails(newVariantId, true);
Expand All @@ -175,7 +196,6 @@ export const useProductPage = () => {
[
selectedProperties,
selectablePropertyNames,
getAvailableValues,
findVariantId,
variantId,
allVariants,
Expand Down
Loading
Loading