Code commenting & making code better

The same
This commit is contained in:
RailTH
2024-05-17 14:52:16 +11:00
parent 03974cb28f
commit 1c4aef92e8
21 changed files with 248 additions and 186 deletions

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.1 on 2024-05-14 07:21
# Generated by Django 4.1 on 2024-05-16 07:15
import django.core.validators
from django.db import migrations, models
@@ -61,7 +61,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(db_index=True, primary_key=True, serialize=False, unique=True, verbose_name='ID Отзыва')),
('commentary', models.TextField(max_length=300, verbose_name='Комментарий отзыва')),
('rate', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)], verbose_name='Оценка')),
('icons', models.TextField(null=True, verbose_name='Изображение отзыва в BASE64')),
('icons', models.TextField(blank=True, null=True, verbose_name='Изображение отзыва в BASE64')),
('date', models.DateTimeField(auto_now=True, verbose_name='Дата создания отзыва')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='SusMarketBackend.product')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='SusMarketBackend.user')),

View File

@@ -1,7 +1,7 @@
{
"files": {
"main.css": "/static/css/main.f8545ce2.css",
"main.js": "/static/js/main.142d0adb.js",
"main.js": "/static/js/main.29450137.js",
"static/media/scam-image.png": "/static/media/scam-image.c6c14289dc251ba2d2b1.png",
"static/media/info-page__railth-avatar.png": "/static/media/info-page__railth-avatar.cbf11c43b5ef243b38c0.png",
"static/media/add.webp": "/static/media/add.cd69f1e2a8c91109db0f.webp",
@@ -14,10 +14,10 @@
"static/media/rating__filled-star-icon.svg": "/static/media/rating__filled-star-icon.dc7d908d4d943b7f3b56.svg",
"index.html": "/index.html",
"main.f8545ce2.css.map": "/static/css/main.f8545ce2.css.map",
"main.142d0adb.js.map": "/static/js/main.142d0adb.js.map"
"main.29450137.js.map": "/static/js/main.29450137.js.map"
},
"entrypoints": [
"static/css/main.f8545ce2.css",
"static/js/main.142d0adb.js"
"static/js/main.29450137.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>SusMarket</title><link rel="manifest" href="/manifest.json"/><script defer="defer" src="/static/js/main.142d0adb.js"></script><link href="/static/css/main.f8545ce2.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>SusMarket</title><link rel="manifest" href="/manifest.json"/><script defer="defer" src="/static/js/main.29450137.js"></script><link href="/static/css/main.f8545ce2.css" rel="stylesheet"></head><body><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,6 @@
import React, { useState, useEffect } from "react";
import { Routes, Route } from 'react-router-dom';
import axios from 'axios';
import HomePage from "./pages/HomePage";
import PaymentPage from "./pages/PaymentPage";
import ProductPage from "./pages/ProductPage";
@@ -6,24 +9,26 @@ import ScamPage from "./pages/ScamPage";
import InfoPage from "./pages/InfoPage";
import Header from "./components/Header";
import PopupMap from "./components/PopupMap";
import React, { useState, useEffect } from "react";
import { Routes, Route } from 'react-router-dom';
import { Product, Category } from "./utils/types";
import axios from 'axios';
interface AppPopupMapState {
isPopupMapVisible: boolean;
}
export default function App() {
// Состояние для отображения/скрытия карты
const [state, setState] = useState<AppPopupMapState>({
isPopupMapVisible: false,
});
// Массив товаров
const [products, setProducts] = useState<Product[]>([]);
// Выбранная категория или все категории
const [selectedCategory, setSelectedCategory] = useState<Category | 'all'>('all');
// Поисковый запрос
const [searchQuery, setSearchQuery] = useState('');
// Получение товаров при загрузке компонента
useEffect(() => {
axios.get('http://127.0.0.1:8000/api/get/products')
.then(response => {
@@ -34,37 +39,56 @@ export default function App() {
});
}, []);
// Функция для переключения отображения/скрытия карты
const togglePopupMap = () => {
setState((prevState) => ({
...prevState,
isPopupMapVisible: !prevState.isPopupMapVisible,
}));
setState((prevState) => (
{
...prevState,
isPopupMapVisible: !prevState.isPopupMapVisible,
}
));
};
// Обработчик изменения поискового запроса
const handleSearchChange = (query: string) => {
setSearchQuery(query);
};
// Фильтрация продуктов по выбранной категории и поисковому запросу
const filteredProducts = products.filter(product =>
(selectedCategory === 'all' || product.category_id === selectedCategory.id) &&
product.title.toLowerCase().includes(searchQuery.toLowerCase())
);
// Обработчик выбора категории
const handleSelectCategory = (category: Category | 'all') => {
setSelectedCategory(category);
};
return (
<>
<Header togglePopupMap={togglePopupMap} onSelectCategory={handleSelectCategory} onSearchChange={handleSearchChange}/>
{/* Шапка сайта */}
<Header
togglePopupMap={togglePopupMap}
onSelectCategory={handleSelectCategory}
onSearchChange={handleSearchChange}
/>
{/* Карта */}
{state.isPopupMapVisible && <PopupMap togglePopupMap={togglePopupMap}/>}
{/* Основной контент */}
<main className="main">
<Routes>
{/* Главная страница */}
<Route path="/" element={<HomePage products={filteredProducts}/>}/>
{/* Страница профиля */}
<Route path="profile/*" element={<ProfilePage />}/>
{/* Страница продукта */}
<Route path="product/:id" element={<ProductPage/>}/>
{/* Страница оплаты */}
<Route path="payment" element={<PaymentPage />}/>
{/* Страница с описанием */}
<Route path="scam" element={<ScamPage />}/>
{/* Страница информации */}
<Route path="info" element={<InfoPage />}/>
</Routes>
</main>

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useState} from "react";
import React, { useEffect, useState, useCallback } from "react";
import axios from "axios";
import { Category } from "../utils/types";
@@ -8,32 +8,40 @@ interface CatalogMenuProps {
}
export default function CatalogMenu({ toggleCatalogMenu, onSelectCategory }: CatalogMenuProps): JSX.Element {
const [categories, setCategories] = useState<Category[]>([]); //состояние для категорий
useEffect(() => { //запрос к api для получения категорий
const fetchCategories = async () => {
try {
const [categories, setCategories] = useState<Category[]>([]);
const fetchCategories = useCallback(async () => {
try {
const response = await axios.get('http://127.0.0.1:8000/api/get/category');
setCategories(response.data.categories);
} catch (error) {
} catch (error) {
console.error(`There was an error retrieving the data: ${error}`);
}
};
}
}, []);
useEffect(() => {
fetchCategories();
}, []);
return(
}, [fetchCategories]);
return (
<>
<div className="background-blackout" onClick={toggleCatalogMenu}></div>
<ul className="catalog-menu">
{categories.map((category) => (
<li key={category.id} className="catalog-menu__point-li" onClick={() => onSelectCategory(category)}>
<img className="catalog-menu__category-icon" src={category.image} alt={category.title} />
{category.title}
</li>
<li
key={category.id}
className="catalog-menu__point-li"
onClick={() => onSelectCategory(category)}
>
<img
className="catalog-menu__category-icon"
src={category.image}
alt={category.title}
/>
{category.title}
</li>
))}
</ul>
</>
)
}
);
}

View File

@@ -14,35 +14,22 @@ interface HeaderProps {
onSearchChange: (query: string) => void;
}
interface HeaderCatalogMenuState {
isCatalogMenuVisible: boolean;
}
interface HeaderLoginMenuState {
isLoginMenuVisible: boolean;
}
export default function Header({ togglePopupMap, onSelectCategory, onSearchChange }: HeaderProps): JSX.Element {
const [isCatalogMenuVisible, setIsCatalogMenuVisible] = useState(false);
const [isLoginMenuVisible, setIsLoginMenuVisible] = useState(false);
const navigate = useNavigate();
const toggleCatalogMenu = () => {
setIsCatalogMenuVisible(!isCatalogMenuVisible);
setIsCatalogMenuVisible(prevState => !prevState);
};
const toggleLoginMenu = () => {
setIsLoginMenuVisible(!isLoginMenuVisible);
setIsLoginMenuVisible(prevState => !prevState);
};
const handleProfileClick = () => {
const userCookie = Cookies.get('user');
if (userCookie) {
navigate('/profile');
} else {
toggleLoginMenu();
}
userCookie ? navigate('/profile') : toggleLoginMenu();
};
const resetCategoryFilter = () => {

View File

@@ -23,11 +23,7 @@ export default function LoginMenu({ toggleLoginMenu }: LoginMenuProps): JSX.Elem
let response;
if (isRegistering) {
// Регистрация пользователя
const params = new URLSearchParams({
login: login,
password: password
});
response = await axios.get(`http://127.0.0.1:8000/api/post/user?${params.toString()}`);
response = await axios.get(`http://127.0.0.1:8000/api/post/user?login=${encodeURIComponent(login)}&password=${encodeURIComponent(password)}`);
} else {
// Вход в систему
response = await axios.get(`http://127.0.0.1:8000/api/get/user?login=${encodeURIComponent(login)}&password=${encodeURIComponent(password)}`);

View File

@@ -20,10 +20,16 @@ export default function PopupMap({ togglePopupMap }: PopupMapProps): JSX.Element
<div className="popup-map__menu-div">
<div className="menu-div__container-div">
<div className="menu-div__delivery-div">
<button className={selectedButton === 1 ? 'delivery-div__delivery-button delivery-div__delivery-button_selected' : 'delivery-div__delivery-button'} onClick={() => handleButtonClick(1)}>
<button
className={`delivery-div__delivery-button ${selectedButton === 1 ? 'delivery-div__delivery-button_selected' : ''}`}
onClick={() => handleButtonClick(1)}
>
Самовывоз
</button>
<button className={selectedButton === 2 ? 'delivery-div__delivery-button delivery-div__delivery-button_selected' : 'delivery-div__delivery-button'} onClick={() => handleButtonClick(2)}>
<button
className={`delivery-div__delivery-button ${selectedButton === 2 ? 'delivery-div__delivery-button_selected' : ''}`}
onClick={() => handleButtonClick(2)}
>
Курьером
</button>
</div>

View File

@@ -2,7 +2,6 @@ import React from "react";
import { Link } from "react-router-dom";
import '../ProfileStyle.scss';
import ProfileInfo from "./ProfileInfo";
// import ProductCard from "./ProductCard";
export default function ProfilePurchases() {
return(
@@ -18,9 +17,7 @@ export default function ProfilePurchases() {
<div className="purchases-container">
<ProfileInfo />
<div className="purchases-div">
{/* <ProductCard ProductImg={ProductImage} ProductName="Абеме" Price={150}/>
<ProductCard ProductImg={ProductImage} ProductName="Абеме" Price={1234523453}/>
<ProductCard ProductImg={ProductImage} ProductName="Абеме" Price={10}/> */}
</div>
</div>
</section>

View File

@@ -1,4 +1,5 @@
import React from "react";
import React, { useState, useEffect } from "react";
import axios from "axios";
import { Reviews } from "../utils/types";
import "../index.scss";
import UserAvatar from "../assets/img/templateUser-avatar.png";
@@ -7,57 +8,49 @@ type ReviewProps = {
review: Reviews;
};
export default function Review({ review }: ReviewProps) { //соответствие типов данных в review с указанными типами и свойствами в интерфейсе Reviews
const readableDate = new Date(review.date).toLocaleDateString('ru-RU'); //приводит дату отзыва из запроса к api в читаемый вид (чч/мм/гг)
return(
export default function Review({ review }: ReviewProps) {
const [userName, setUserName] = useState<string>("");
const readableDate = new Date(review.date).toLocaleDateString('ru-RU');
useEffect(() => {
const fetchUserName = async () => {
try {
const response = await axios.get(`http://127.0.0.1:8000/api/get/user/${review.user_id}`);
if (response.status === 200) {
setUserName(response.data.login);
}
} catch (error) {
console.error('Ошибка при получении логина пользователя:', error);
}
};
fetchUserName();
}, [review.user_id]);
return (
<article className="review-article">
<div className="review-article__review-container">
<div className="review-container__user-info">
<img className="user-info__user-avatar" src={UserAvatar} alt="Review user avatar" />
<h4 className="user-info__user-name">
{review.user_id}
{userName}
</h4>
</div>
<div className="review-container__review-info">
<div className="review-info__star-rate">
<input
type="radio"
className="star-rate__star-radio"
value={1}
aria-label="Плохо"
checked={review.rate === 1}
/>
<input
type="radio"
className="star-rate__star-radio"
value={2}
aria-label="Удовлетворительно"
checked={review.rate === 2}
/>
<input
type="radio"
className="star-rate__star-radio"
value={3}
aria-label="Нормально"
checked={review.rate === 3}
/>
<input
type="radio"
className="star-rate__star-radio"
value={4}
aria-label="Хорошо"
checked={review.rate === 4}
/>
<input
type="radio"
className="star-rate__star-radio"
value={5}
aria-label="Отлично"
checked={review.rate === 5}
/>
{[1, 2, 3, 4, 5].map(rate => (
<input
key={rate}
type="radio"
className="star-rate__star-radio"
value={rate}
aria-label={rate === 1 ? "Плохо" : rate === 2 ? "Удовлетворительно" : rate === 3 ? "Нормально" : rate === 4 ? "Хорошо" : "Отлично"}
checked={review.rate === rate}
readOnly
/>
))}
</div>
<time className="review-info__review-date" dateTime="2019-09-09">
<time className="review-info__review-date" dateTime={new Date(review.date).toISOString()}>
{readableDate}
</time>
</div>
@@ -65,7 +58,7 @@ export default function Review({ review }: ReviewProps) { //соответств
<p className="review-article__text-p">
{review.commentary}
</p>
<img className="review-article__product-image" src={review.icons} alt="Review product" />
{review.icons && <img className="review-article__product-image" src={review.icons} alt="Review product" />}
</article>
)
}
);
}

View File

@@ -1,16 +1,26 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import '../ProductStyle.scss';
import ImageAttachIcon from "../assets/icons/review-form__add-image-icon.svg";
import { motion } from 'framer-motion';
import axios from 'axios';
import Cookies from 'js-cookie';
interface ReviewState {
text: string;
rating: number;
image: File | null;
image?: string | ArrayBuffer | null; // Изображение может быть в формате base64
}
export default function ReviewForm() {
const [review, setReview] = useState<ReviewState>({ text: '', rating: 1, image: null });
export default function ReviewForm({ productId }: { productId: string }) {
const [review, setReview] = useState<ReviewState>({ text: '', rating: 1 });
const [userId, setUserId] = useState<string | null>(null);
useEffect(() => {
const userIdFromCookie = Cookies.get('id');
if (userIdFromCookie) {
setUserId(userIdFromCookie);
}
}, []);
function handleTextChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
setReview({ ...review, text: event.target.value });
@@ -21,59 +31,85 @@ export default function ReviewForm() {
}
function handleImageChange(event: React.ChangeEvent<HTMLInputElement>) {
if (event.target.files) {
setReview({ ...review, image: event.target.files[0] });
if (event.target.files && event.target.files[0]) {
const reader = new FileReader();
reader.onload = () => {
setReview({ ...review, image: reader.result });
};
reader.readAsDataURL(event.target.files[0]);
}
}
function handleSubmit(event: React.FormEvent) {
async function handleSubmit(event: React.FormEvent) {
event.preventDefault();
console.log(review);
if (!userId) {
console.error('User ID not found!');
return;
}
try {
const formData = new FormData();
formData.append('product_id', productId);
formData.append('text', review.text);
formData.append('rating', String(review.rating));
if (review.image) {
formData.append('image', review.image as string);
}
formData.append('user_id', userId);
await axios.post('http://127.0.0.1:8000/api/post/review', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
console.log('Review submitted successfully!');
// Опционально: добавить логику для обновления списка отзывов на странице после успешной отправки
} catch (error) {
console.error('Error submitting review:', error);
}
}
return(
return (
<form className='product-page__review-form' onSubmit={handleSubmit}>
<h5 className='review-form__heading'>
Оставить отзыв
</h5>
<div className="review-form__stars-container">
{[...Array(5)].map((_, index) => (
<input
<input
key={index}
type="radio"
className="review-form__star-radio"
name="rating"
value={index + 1}
aria-label={`Рейтинг ${index + 1}`}
checked={review.rating === index + 1}
type="radio"
className="review-form__star-radio"
name="rating"
value={index + 1}
aria-label={`Рейтинг ${index + 1}`}
checked={review.rating === index + 1}
onChange={handleRatingChange}
/>
))}
</div>
<textarea
className='review-form__textarea'
cols={30}
rows={5}
placeholder='Комментарий'
value={review.text}
<textarea
className='review-form__textarea'
cols={30}
rows={5}
placeholder='Комментарий'
value={review.text}
onChange={handleTextChange}
/>
<label htmlFor="review-image" className='review-form__image-attach'>
<img src={ImageAttachIcon} alt="Прикрепить изображение"/>
<img src={ImageAttachIcon} alt="Прикрепить изображение" />
</label>
<input
className='review-form__image-input'
type="file"
name="review image"
id="review-image"
accept='.png, .jpg, .jpeg'
<input
className='review-form__image-input'
type="file"
name="review image"
id="review-image"
accept='.png, .jpg, .jpeg'
onChange={handleImageChange}
/>
<motion.button
className='review-form__send-button'
<motion.button
className='review-form__send-button'
type='submit'
whileTap={{scale: 0.98}}
transition={{duration: 0.2, type: "spring"}}
whileTap={{ scale: 0.98 }}
transition={{ duration: 0.2, type: "spring" }}
>
Отправить отзыв
</motion.button>

View File

@@ -1,15 +1,15 @@
import React from "react";
import { Link } from "react-router-dom";
import '../HomeStyle.scss';
import ProductCard from "../components/ProductCard";
import Banner from "../components/AdBanner";
import { Product } from "../utils/types";
import { Link } from "react-router-dom";
type HomePageProps = {
products: Product[];
}
export default function HomePage({ products }: HomePageProps) { //соответствие типов данных в products с указанными типами и свойствами в интерфейсе Product
export default function HomePage({ products }: HomePageProps) {
return(
<section className="home-page">
<Banner />
@@ -18,16 +18,17 @@ export default function HomePage({ products }: HomePageProps) { //соответ
<Link to={`/product/${product.id}`} key={product.id}>
<ProductCard
title={product.title}
icons={product.icons}
price={product.price}
category_id={product.category_id}
id={product.id}
description={product.description}
tags={product.tags}
id={product.id}
category_id={product.category_id}
price={product.price}
icons={product.icons}
description={product.description}
/>
</Link>
</Link>
))}
</div>
</section>
);
}
}

View File

@@ -1,16 +1,17 @@
import React from "react";
import DevCard from "../components/DevCard";
import "../InfoPageStyle.scss";
import RailTHAvatar from "../assets/img/info-page__railth-avatar.png"
import NoKesspenAvatar from "../assets/img/info-page__no-kesspen-avatar.png"
import RailTHAvatar from "../assets/img/info-page__railth-avatar.png";
import NoKesspenAvatar from "../assets/img/info-page__no-kesspen-avatar.png";
export default function InfoPage() {
return(
return (
<section className="info-page">
{/* Компонент DevCard отображает информацию о разработчике */}
<DevCard
avatar={NoKesspenAvatar}
name="No_Kesspen"
info="Backend разработчик"
info="Backend & Frontend разработчик"
url="https://github.com/KessPenGames"
/>
<DevCard
@@ -20,5 +21,5 @@ export default function InfoPage() {
url="https://github.com/Rail-TH"
/>
</section>
)
}
);
}

View File

@@ -1,37 +1,50 @@
import React, { useState } from "react";
import '../PaymentStyle.scss';
import { useLocation } from 'react-router-dom';
// Компонент страницы оплаты
export default function PaymentPage() {
const [ccNumber, setCcNumber] = useState(""); //состояние номера кредитной карты
const [valueDate, setValueDate] = useState<number | ''>(''); //состояние даты истечения срока карты
const [valueCode, setValueCode] = useState<number | ''>(''); //состояние кода безопасности карты
const formatAndSetCcNumber = (e: React.ChangeEvent<HTMLInputElement>) => { //в ccNumber максимум 16 цифр, разбивка пробелами по 4
// Состояние номера кредитной карты
const [ccNumber, setCcNumber] = useState("");
// Состояние даты истечения срока карты
const [valueDate, setValueDate] = useState<number | ''>('');
// Состояние кода безопасности карты
const [valueCode, setValueCode] = useState<number | ''>('');
// Получение параметров из URL
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
// Получение цены из параметров URL
const price = queryParams.get('price');
// Функция для форматирования и установки номера кредитной карты
const formatAndSetCcNumber = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputVal = e.target.value.replace(/ /g, "");
let inputNumbersOnly = inputVal.replace(/\D/g, "");
if (inputNumbersOnly.length > 16) {
inputNumbersOnly = inputNumbersOnly.substr(0, 16);
}
const splits = inputNumbersOnly.match(/.{1,4}/g);
let spacedNumber = "";
if (splits) {
spacedNumber = splits.join(" ");
}
setCcNumber(spacedNumber);
};
const handleChangeDate = (event: React.ChangeEvent<HTMLInputElement>) => { //valueDate не более 4-х цифр
// Функция для обработки изменения даты истечения срока карты
const handleChangeDate = (event: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = event.target.value;
if (inputValue.length <= 4) {
setValueDate(inputValue === '' ? '' : Number(inputValue));
}
};
const handleChangeCode = (event: React.ChangeEvent<HTMLInputElement>) => { //valueCode не более 3-х цифр
// Функция для обработки изменения кода безопасности карты
const handleChangeCode = (event: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = event.target.value;
if (inputValue.length <= 3) {
setValueCode(inputValue === '' ? '' : Number(inputValue));
@@ -40,22 +53,21 @@ export default function PaymentPage() {
return(
<section className="payment-page">
<h2 className="payment-page__price">
</h2>
{/* Отображение цены */}
<h2 className="payment-page__price">{price} </h2>
<div className="payment-page__payment-card">
<h3 className="payment-card__heading">
Оплата картой
</h3>
<input className="payment-card__input" type="text" name="" id="" placeholder="Номер" value={ccNumber} onChange={formatAndSetCcNumber}/>
<h3 className="payment-card__heading"> Оплата картой </h3>
{/* Ввод номера кредитной карты */}
<input className="payment-card__input" type="text" placeholder="Номер" value={ccNumber} onChange={formatAndSetCcNumber}/>
<div className="payment-card__inputs-group">
<input className="payment-card__input" type="number" name="" id="" placeholder="ММ/ГГ" value={valueDate} onChange={handleChangeDate}/>
<input className="payment-card__input" type="number" name="" id="" placeholder="CVC/CVV" value={valueCode} onChange={handleChangeCode}/>
{/* Ввод даты истечения срока карты */}
<input className="payment-card__input" type="number" placeholder="ММ/ГГ" value={valueDate} onChange={handleChangeDate}/>
{/* Ввод кода безопасности карты */}
<input className="payment-card__input" type="number" placeholder="CVC/CVV" value={valueCode} onChange={handleChangeCode}/>
</div>
</div>
<a href="scam" className="payment-page__pay-link">
Оплатить
</a>
{/* Кнопка для оплаты */}
<a href="scam" className="payment-page__pay-link"> Оплатить </a>
</section>
)
}

View File

@@ -5,7 +5,7 @@ import axios from 'axios';
import '../ProductStyle.scss';
import ShareIcon from "../assets/icons/share-icon.svg";
import ReviewForm from '../components/ReviewForm';
import { useParams } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
export default function ProductPage() {
function trimText(text: string, limit: number) { //сокращение описания
@@ -87,9 +87,9 @@ export default function ProductPage() {
<span className="product-page__price-span">
{product.price}
</span>
<a href="/payment" className="product-page__buy-link">
<Link to={`/payment?price=${product.price}`} className="product-page__buy-link">
Купить
</a>
</Link>
</div>
</div>
</div>
@@ -144,7 +144,7 @@ export default function ProductPage() {
))}
</div>
</div>
<ReviewForm />
<ReviewForm productId={product.id.toLocaleString('ru-RU')}/>
<div className='product-page__reviews-container'>
{reviews.map((review) => (
<Review key={review.id} review={review} />
@@ -153,4 +153,5 @@ export default function ProductPage() {
</section>
</section>
)
}
}

View File

@@ -15,4 +15,4 @@ export default function ProfilePage() {
</Routes>
</section>
)
}
}