mirror of
https://github.com/yawaflua/SusMarket.git
synced 2026-04-24 16:50:41 +03:00
Fixes & commentaries
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.b9cb408a.css",
|
||||
"main.js": "/static/js/main.08d74509.js",
|
||||
"main.js": "/static/js/main.d5c997c3.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.b9cb408a.css.map": "/static/css/main.b9cb408a.css.map",
|
||||
"main.08d74509.js.map": "/static/js/main.08d74509.js.map"
|
||||
"main.d5c997c3.js.map": "/static/js/main.d5c997c3.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.b9cb408a.css",
|
||||
"static/js/main.08d74509.js"
|
||||
"static/js/main.d5c997c3.js"
|
||||
]
|
||||
}
|
||||
@@ -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.08d74509.js"></script><link href="/static/css/main.b9cb408a.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.d5c997c3.js"></script><link href="/static/css/main.b9cb408a.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
@@ -60,7 +60,7 @@ export default function App() {
|
||||
{state.isPopupMapVisible && <PopupMap togglePopupMap={togglePopupMap}/>}
|
||||
<main className="main">
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage products={filteredProducts} selectedCategory={selectedCategory}/>}/>
|
||||
<Route path="/" element={<HomePage products={filteredProducts}/>}/>
|
||||
<Route path="profile/*" element={<ProfilePage />}/>
|
||||
<Route path="product/:id" element={<ProductPage/>}/>
|
||||
<Route path="payment" element={<PaymentPage />}/>
|
||||
|
||||
@@ -8,21 +8,20 @@ interface CatalogMenuProps {
|
||||
}
|
||||
|
||||
export default function CatalogMenu({ toggleCatalogMenu, onSelectCategory }: CatalogMenuProps): JSX.Element {
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
const [categories, setCategories] = useState<Category[]>([]); //состояние для категорий
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => { //запрос к api для получения категорий
|
||||
const fetchCategories = async () => {
|
||||
try {
|
||||
try {
|
||||
const response = await axios.get('http://127.0.0.1:8000/api/get/category');
|
||||
setCategories(response.data.categories);
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
console.error(`There was an error retrieving the data: ${error}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
fetchCategories();
|
||||
}, []);
|
||||
}, []);
|
||||
|
||||
return(
|
||||
<>
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import React from 'react';
|
||||
import { DeveloperCard } from "../utils/types"
|
||||
|
||||
interface DeveloperCardProps {
|
||||
avatar: string;
|
||||
name: string;
|
||||
info: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function DevCard({ avatar, name, info, url }: DeveloperCardProps) {
|
||||
export default function DevCard({ avatar, name, info, url }: DeveloperCard) {
|
||||
return (
|
||||
<div className="info-page__dev-card">
|
||||
<div className="dev-card__inner">
|
||||
|
||||
@@ -7,8 +7,8 @@ type ReviewProps = {
|
||||
review: Reviews;
|
||||
};
|
||||
|
||||
export default function Review({ review }: ReviewProps) {
|
||||
const readableDate = new Date(review.date).toLocaleDateString('ru-RU');
|
||||
export default function Review({ review }: ReviewProps) { //соответствие типов данных в review с указанными типами и свойствами в интерфейсе Reviews
|
||||
const readableDate = new Date(review.date).toLocaleDateString('ru-RU'); //приводит дату отзыва из запроса к api в читаемый вид (чч/мм/гг)
|
||||
|
||||
return(
|
||||
<article className="review-article">
|
||||
|
||||
@@ -2,15 +2,14 @@ import React from "react";
|
||||
import '../HomeStyle.scss';
|
||||
import ProductCard from "../components/ProductCard";
|
||||
import Banner from "../components/AdBanner";
|
||||
import { Product, Category } from "../utils/types";
|
||||
import { Product } from "../utils/types";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface HomePageProps {
|
||||
type HomePageProps = {
|
||||
products: Product[];
|
||||
selectedCategory: Category | 'all';
|
||||
}
|
||||
|
||||
export default function HomePage({ products, selectedCategory }: HomePageProps) {
|
||||
export default function HomePage({ products }: HomePageProps) { //соответствие типов данных в products с указанными типами и свойствами в интерфейсе Product
|
||||
return(
|
||||
<section className="home-page">
|
||||
<Banner />
|
||||
|
||||
@@ -2,40 +2,36 @@ import React, { useState } from "react";
|
||||
import '../PaymentStyle.scss';
|
||||
|
||||
export default function PaymentPage() {
|
||||
let price = 150
|
||||
const [ccNumber, setCcNumber] = useState(""); //состояние номера кредитной карты
|
||||
const [valueDate, setValueDate] = useState<number | ''>(''); //состояние даты истечения срока карты
|
||||
const [valueCode, setValueCode] = useState<number | ''>(''); //состояние кода безопасности карты
|
||||
|
||||
const [ccNumber, setCcNumber] = useState("");
|
||||
const [valueDate, setValueDate] = useState<number | ''>('');
|
||||
const [valueCode, setValueCode] = useState<number | ''>('');
|
||||
|
||||
const formatAndSetCcNumber = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const inputVal = e.target.value.replace(/ /g, ""); //remove all the empty spaces in the input
|
||||
let inputNumbersOnly = inputVal.replace(/\D/g, ""); // Get only digits
|
||||
const formatAndSetCcNumber = (e: React.ChangeEvent<HTMLInputElement>) => { //в ccNumber максимум 16 цифр, разбивка пробелами по 4
|
||||
const inputVal = e.target.value.replace(/ /g, "");
|
||||
let inputNumbersOnly = inputVal.replace(/\D/g, "");
|
||||
|
||||
if (inputNumbersOnly.length > 16) {
|
||||
//If entered value has a length greater than 16 then take only the first 16 digits
|
||||
inputNumbersOnly = inputNumbersOnly.substr(0, 16);
|
||||
}
|
||||
|
||||
// Get nd array of 4 digits per an element EX: ["4242", "4242", ...]
|
||||
|
||||
const splits = inputNumbersOnly.match(/.{1,4}/g);
|
||||
|
||||
let spacedNumber = "";
|
||||
if (splits) {
|
||||
spacedNumber = splits.join(" "); // Join all the splits with an empty space
|
||||
spacedNumber = splits.join(" ");
|
||||
}
|
||||
|
||||
setCcNumber(spacedNumber); // Set the new CC number
|
||||
setCcNumber(spacedNumber);
|
||||
};
|
||||
|
||||
const handleChangeDate = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handleChangeDate = (event: React.ChangeEvent<HTMLInputElement>) => { //valueDate не более 4-х цифр
|
||||
const inputValue = event.target.value;
|
||||
if (inputValue.length <= 4) {
|
||||
setValueDate(inputValue === '' ? '' : Number(inputValue));
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeCode = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handleChangeCode = (event: React.ChangeEvent<HTMLInputElement>) => { //valueCode не более 3-х цифр
|
||||
const inputValue = event.target.value;
|
||||
if (inputValue.length <= 3) {
|
||||
setValueCode(inputValue === '' ? '' : Number(inputValue));
|
||||
@@ -45,7 +41,7 @@ export default function PaymentPage() {
|
||||
return(
|
||||
<section className="payment-page">
|
||||
<h2 className="payment-page__price">
|
||||
{price} ₽
|
||||
₽
|
||||
</h2>
|
||||
<div className="payment-page__payment-card">
|
||||
<h3 className="payment-card__heading">
|
||||
|
||||
@@ -8,21 +8,29 @@ import ReviewForm from '../components/ReviewForm';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
export default function ProductPage() {
|
||||
function trimText(text: string, limit: number) {
|
||||
function trimText(text: string, limit: number) { //сокращение описания
|
||||
return text.length > limit ? text.substring(0, limit) + '...' : text;
|
||||
}
|
||||
|
||||
const { id } = useParams();
|
||||
const [product, setProduct] = useState<Product | null>(null);
|
||||
const [reviews, setReviews] = useState<Reviews[]>([]);
|
||||
const [averageRating, setAverageRating] = useState<number>(0);
|
||||
const [isDataFetched, setIsDataFetched] = useState(false);
|
||||
const { id } = useParams(); //возвращает id товара из Url
|
||||
const [product, setProduct] = useState<Product | null>(null); //состояние для данных о товаре
|
||||
const [reviews, setReviews] = useState<Reviews[]>([]); //состаяние для отзывов
|
||||
const [averageRating, setAverageRating] = useState<number>(0); //состояние для средней арифметической оценки товара
|
||||
const [isDataFetched, setIsDataFetched] = useState(false); //состояние для отслеживания кэширования данных из запроса
|
||||
const totalReviews = reviews.length; //количество отзывов
|
||||
const countReviewsByRate = (rate: number): number => { //подсчёт отзывов с данной оценкой
|
||||
return reviews.filter(review => review.rate === rate).length;
|
||||
};
|
||||
const percentageOfRate = (rate: number): number => { //расчёт процента отзывов с данной оценкой от количетсва всех отзывов
|
||||
const count = countReviewsByRate(rate);
|
||||
return (count / totalReviews) * 100;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => { //запрос к api данных о товаре
|
||||
axios
|
||||
.get('http://127.0.0.1:8000/api/get/products')
|
||||
.then(response => {
|
||||
const productData = response.data.products.find(
|
||||
const productData = response.data.products.find( //"извлечение" данных о товаре из массива по его id
|
||||
(item: Product) => item.id.toString() === id
|
||||
);
|
||||
setProduct(productData);
|
||||
@@ -32,15 +40,20 @@ export default function ProductPage() {
|
||||
});
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDataFetched) {
|
||||
useEffect(() => { //запрос к api отзывов у товара
|
||||
if (!isDataFetched) { //проверка на кэширование данных
|
||||
axios
|
||||
.get(`http://127.0.0.1:8000/api/get/reviews/${id}`)
|
||||
.then(response => {
|
||||
setReviews(response.data.review);
|
||||
const totalRating = response.data.review.reduce((acc: number, review: Reviews) => acc + review.rate, 0);
|
||||
const average = totalRating / response.data.review.length;
|
||||
setAverageRating(average);
|
||||
const totalRating = response.data.review.reduce((acc: number, review: Reviews) => acc + review.rate, 0); //общий рейтинг отзывов
|
||||
const average = totalRating / response.data.review.length; //средннее арифметический рейтинг всех отзывов
|
||||
if (response.data.review.length > 0) { //проверка на наличие отзывов
|
||||
setAverageRating(average);
|
||||
}
|
||||
else {
|
||||
setAverageRating(0);
|
||||
}
|
||||
setIsDataFetched(true);
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -89,7 +102,7 @@ export default function ProductPage() {
|
||||
{product.description}
|
||||
</p>
|
||||
<ul className="product-page__tags-ul">
|
||||
{(product.tags.split('|')).map((tag, index) => (
|
||||
{(product.tags.split('|')).map((tag, index) => ( //разделение тегов
|
||||
<li key={index} className="product-page__tag-li">
|
||||
{tag}
|
||||
</li>
|
||||
@@ -107,7 +120,7 @@ export default function ProductPage() {
|
||||
</span>
|
||||
<div className="rate-block__star-rating">
|
||||
<div className="star-rating__back-stars">
|
||||
{'★★★★★'.split('').map((star, i) => (
|
||||
{'★★★★★'.split('').map((star, i) => ( //пожалуйста, не спрашивайте как это работает
|
||||
<span key={`back-star-${i}`}>{star}</span>
|
||||
))}
|
||||
<div className="star-rating__front-stars" style={{ width: `${(averageRating / 5) * 100}%` }}>
|
||||
@@ -119,46 +132,16 @@ export default function ProductPage() {
|
||||
</div>
|
||||
</div>
|
||||
<div className='rate-block__progressbars-group'>
|
||||
<div className='progressbars-group__progressbar-container'>
|
||||
<span className='rate-progressbar__rate-number'>
|
||||
5
|
||||
</span>
|
||||
<div className='progressbar-container__progressbar'>
|
||||
<div className='progressbar__active-line'></div>
|
||||
</div>
|
||||
{[5, 4, 3, 2, 1].map(rate => (
|
||||
<div className='progressbars-group__progressbar-container' key={rate}>
|
||||
<span className='rate-progressbar__rate-number'>
|
||||
{rate}
|
||||
</span>
|
||||
<div className='progressbar-container__progressbar'>
|
||||
<div className='progressbar__active-line' style={{ width: `${percentageOfRate(rate)}%` }}></div>
|
||||
</div>
|
||||
<div className='progressbars-group__progressbar-container'>
|
||||
<span className='rate-progressbar__rate-number'>
|
||||
4
|
||||
</span>
|
||||
<div className='progressbar-container__progressbar'>
|
||||
<div className='progressbar__active-line'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='progressbars-group__progressbar-container'>
|
||||
<span className='rate-progressbar__rate-number'>
|
||||
3
|
||||
</span>
|
||||
<div className='progressbar-container__progressbar'>
|
||||
<div className='progressbar__active-line'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='progressbars-group__progressbar-container'>
|
||||
<span className='rate-progressbar__rate-number'>
|
||||
2
|
||||
</span>
|
||||
<div className='progressbar-container__progressbar'>
|
||||
<div className='progressbar__active-line'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='progressbars-group__progressbar-container'>
|
||||
<span className='rate-progressbar__rate-number'>
|
||||
1
|
||||
</span>
|
||||
<div className='progressbar-container__progressbar'>
|
||||
<div className='progressbar__active-line'></div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<ReviewForm />
|
||||
|
||||
@@ -22,4 +22,11 @@ export interface Reviews {
|
||||
product_id: number;
|
||||
rate: number;
|
||||
user_id: number;
|
||||
}
|
||||
|
||||
export interface DeveloperCard {
|
||||
avatar: string;
|
||||
name: string;
|
||||
info: string;
|
||||
url: string;
|
||||
}
|
||||
Reference in New Issue
Block a user