mirror of
https://github.com/yawaflua/SusMarket.git
synced 2025-12-08 19:49:36 +02: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
3
reactapp/build/static/js/main.d5c997c3.js
Normal file
3
reactapp/build/static/js/main.d5c997c3.js
Normal file
File diff suppressed because one or more lines are too long
1
reactapp/build/static/js/main.d5c997c3.js.map
Normal file
1
reactapp/build/static/js/main.d5c997c3.js.map
Normal file
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