From ed1c305cbb94ee1faa102c668fac2d65aef7bb1c Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 11:44:35 +0300 Subject: [PATCH 01/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20docker,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20gockerignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 9 +++++++++ Dockerfile | 33 ++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5bdd9f0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +node_modules +.forgejo +dist +.git +.env* +*.log +.DS_Store +coverage +.vite \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 3b74df8..d780e0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,33 @@ -FROM mkenney/npm:node-11-alpine +# ========== СТАДИЯ 1: СБОРКА ========== +FROM node:20-alpine AS builder -WORKDIR /web/app +WORKDIR /app +# Копируем зависимости +COPY package*.json ./ +RUN npm ci + +# Копируем исходники COPY . . -RUN npm install -RUN npm cache clean --force +# Сборка проекта +RUN npm run build -CMD ["npm", "run", "dev"] +# ========== СТАДИЯ 2: СЕРВЕР ========== +FROM nginx:alpine + +# Копируем собранные файлы из стадии 1 +COPY --from=builder /app/dist /usr/share/nginx/html + +# Конфиг для SPA (чтобы react-router работал) +RUN echo 'server { \ + listen 80; \ + location / { \ + root /usr/share/nginx/html; \ + try_files $uri $uri/ /index.html; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] -- 2.54.0 From f6b59e9a23446e46ad2be6617bf46e7f03c1f526 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 11:56:49 +0300 Subject: [PATCH 02/53] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/store.ts | 1 - src/features/catalog/productsSlice.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/app/store.ts b/src/app/store.ts index 8bd0c79..bed903e 100644 --- a/src/app/store.ts +++ b/src/app/store.ts @@ -1,5 +1,4 @@ import { configureStore } from "@reduxjs/toolkit"; -import catalogReducer from "../features/catalog/productsSlice"; import categoriesReducer from "../features/catalog/categoriesSlice" import productsReducer from "../features/catalog/productsSlice" diff --git a/src/features/catalog/productsSlice.ts b/src/features/catalog/productsSlice.ts index a0b3f85..1126237 100644 --- a/src/features/catalog/productsSlice.ts +++ b/src/features/catalog/productsSlice.ts @@ -2,7 +2,6 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import type {PayloadAction} from "@reduxjs/toolkit"; import {client} from "../../api/client"; import type { Product } from "../../types/product"; -import axios from "axios"; interface FetchParams { categoryId: number; -- 2.54.0 From f270c6c0fe367bd666328baa662817d9395c0ca0 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 12:07:06 +0300 Subject: [PATCH 03/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 44f3321..0ad4e49 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc -b && vite build", + "build": "vite build", + "build:check": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview" }, -- 2.54.0 From df7a3a542cc727d19ce3fd1fe5cf3f55c8b4e9a4 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 12:18:49 +0300 Subject: [PATCH 04/53] . --- src/pages/ItemPage/ItemPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ItemPage/ItemPage.tsx b/src/pages/ItemPage/ItemPage.tsx index 3436661..9839a1d 100644 --- a/src/pages/ItemPage/ItemPage.tsx +++ b/src/pages/ItemPage/ItemPage.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { useAppDispatch, useAppSelector } from "../../app/hooks"; import { fetchProductById } from "../../features/catalog/productsSlice"; -import styles from "./ProductPage.module.css"; +import styles from "./ItemPage.module.css"; import type { CategoryAtributes, CategoryAtrVals } from "../../types/categories"; const ItemPage = () => { -- 2.54.0 From 5de57cc7ad6e6e8b4a6258346d75198f6976720d Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 12:56:47 +0300 Subject: [PATCH 05/53] =?UTF-8?q?=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=83?= =?UTF-8?q?=D1=8E=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/client.ts | 2 +- src/components/ModalRequestForm/ModalRequestForm.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/client.ts b/src/api/client.ts index 76e08df..0f4e6ab 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -3,7 +3,7 @@ import axios, { AxiosInstance } from 'axios'; class ApiClient { private axiosInstance: AxiosInstance; - constructor(baseURL: string = import.meta.env.VITE_API_URL) { + constructor(baseURL: string = 'https://pvh.projects.rustprogersteam.ru') { this.axiosInstance = axios.create({ baseURL, timeout: 10000, diff --git a/src/components/ModalRequestForm/ModalRequestForm.tsx b/src/components/ModalRequestForm/ModalRequestForm.tsx index f197dd7..07c2131 100644 --- a/src/components/ModalRequestForm/ModalRequestForm.tsx +++ b/src/components/ModalRequestForm/ModalRequestForm.tsx @@ -65,7 +65,7 @@ const ModalRequestForm: React.FC = ({ open, onClose }) => { // ✅ Отправка данных на бэкенд const sendToBackend = async (data: FormData): Promise => { try { - const response = await fetch(`/api/requests`, { + const response = await fetch(`/api/email`, { method: "POST", headers: { "Content-Type": "application/json", -- 2.54.0 From b205ca92043bf092ac92624a62334268a51fc041 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 13:23:27 +0300 Subject: [PATCH 06/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=87=D1=82=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ModalRequestForm/ModalRequestForm.tsx | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/components/ModalRequestForm/ModalRequestForm.tsx b/src/components/ModalRequestForm/ModalRequestForm.tsx index 07c2131..b6111d2 100644 --- a/src/components/ModalRequestForm/ModalRequestForm.tsx +++ b/src/components/ModalRequestForm/ModalRequestForm.tsx @@ -7,6 +7,7 @@ import * as yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; import styles from "./ModalRequestForm.module.css"; import Button from "../Button/Button"; +import { client } from "../../api/client"; // ✅ Схема валидации const schema = yup.object().shape({ @@ -64,30 +65,19 @@ const ModalRequestForm: React.FC = ({ open, onClose }) => { // ✅ Отправка данных на бэкенд const sendToBackend = async (data: FormData): Promise => { - try { - const response = await fetch(`/api/email`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - ...data, - source: "website-form", - timestamp: new Date().toISOString(), - }), - }); + try { + const payload = { + ...data, + }; - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const result = await response.json(); - return result.success; - } catch (error) { - console.error("Error sending request:", error); - throw new Error("Не удалось отправить заявку. Попробуйте позже."); - } - }; + const response = await client.post<{ success: boolean }>("/email", payload); + + return response.data.success; + } catch (error) { + console.error("Error sending request:", error); + throw new Error("Не удалось отправить заявку. Попробуйте позже."); + } +}; // ✅ Submit const onSubmit = async (data: FormData) => { -- 2.54.0 From 053128ca50b688ff1fad6267eb6a1b1b502ad43b Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 13:23:42 +0300 Subject: [PATCH 07/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/client.ts b/src/api/client.ts index 0f4e6ab..3989ee1 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -39,4 +39,4 @@ class ApiClient { } } -export const client = new ApiClient('/api'); \ No newline at end of file +export const client = new ApiClient('https://pvh.projects.rustprogersteam.ru/api'); \ No newline at end of file -- 2.54.0 From cacc69a7d32bed4488a6e66020601ae3b38233b0 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 13:47:23 +0300 Subject: [PATCH 08/53] ... --- src/components/PriceLisForm/PriceLisForm.tsx | 1 - src/features/MainPage/PhoneRequest.tsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/PriceLisForm/PriceLisForm.tsx b/src/components/PriceLisForm/PriceLisForm.tsx index a0837b0..183925f 100644 --- a/src/components/PriceLisForm/PriceLisForm.tsx +++ b/src/components/PriceLisForm/PriceLisForm.tsx @@ -6,7 +6,6 @@ import * as yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; import styles from "./ModalRequestForm.module.css"; import Button from "../Button/Button"; -import axios from "axios"; import { client } from "../../api/client"; // ✅ Схема валидации diff --git a/src/features/MainPage/PhoneRequest.tsx b/src/features/MainPage/PhoneRequest.tsx index 228b614..e35ef02 100644 --- a/src/features/MainPage/PhoneRequest.tsx +++ b/src/features/MainPage/PhoneRequest.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; -import axios from "axios"; import styles from "./MainPage.module.css"; import Button from "../../components/Button/Button"; +import { client } from "../../api/client"; interface Props { onSend?: (phone: string) => Promise; @@ -60,7 +60,7 @@ const PhoneRequest: React.FC = ({ onSend }) => { await onSend(phone); } else { - await axios.post("/api/contact/send-phone", { phone }); + await client.post("/api/contact/send-phone", { phone }); } setSuccess(true); -- 2.54.0 From 941e3ea9df47d0edc2d6cacc57f167e6532301d1 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 18:18:41 +0300 Subject: [PATCH 09/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20http?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/catalogApi.ts | 4 ++-- src/components/ContactProduct/ContactProduct.tsx | 2 +- src/components/PriceLisForm/PriceLisForm.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/catalogApi.ts b/src/api/catalogApi.ts index e145965..8e3960d 100644 --- a/src/api/catalogApi.ts +++ b/src/api/catalogApi.ts @@ -1,4 +1,4 @@ -import axios from "axios"; +/*import axios from "axios"; import type { Product } from "../types/product"; import type { Category } from "../types/categories"; @@ -10,5 +10,5 @@ export const fetchCategoryProducts = async (category: string): Promise => { const response = await axios.get(`https://your-api.com/api/category=${categoryid}`); return response.data; -}; +};*/ diff --git a/src/components/ContactProduct/ContactProduct.tsx b/src/components/ContactProduct/ContactProduct.tsx index bfeedee..82a24e4 100644 --- a/src/components/ContactProduct/ContactProduct.tsx +++ b/src/components/ContactProduct/ContactProduct.tsx @@ -3,7 +3,7 @@ import styles from "./ContactProduct.module.css"; import Button from "../Button/Button"; import { Carousel } from "antd"; import ModalRequestForm from "../ModalRequestForm/ModalRequestForm"; -const imageUrl = "http://sprint-pro.com/images/banners/slide1/t1.png"; +const imageUrl = "https://sprint-pro.com/images/banners/slide1/t1.png"; import image1 from "../../assets/images/mainPage/_.jpg" import image2 from "../../assets/images/mainPage/orig.jpg" diff --git a/src/components/PriceLisForm/PriceLisForm.tsx b/src/components/PriceLisForm/PriceLisForm.tsx index 183925f..5771697 100644 --- a/src/components/PriceLisForm/PriceLisForm.tsx +++ b/src/components/PriceLisForm/PriceLisForm.tsx @@ -62,7 +62,7 @@ const PriceLisForm: React.FC = ({ open, onClose }) => { const sendToBackend = async (data: FormData): Promise => { try{ - const response = await client.post<{success: boolean}>("/api/email", { + const response = await client.post<{success: boolean}>("/email", { ...data, }) -- 2.54.0 From e7699bba77af59f24e2f077b8ffd7a5292c19148 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 2 Apr 2026 19:12:50 +0300 Subject: [PATCH 10/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d780e0d..5bc1652 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN npm ci COPY . . # Сборка проекта -RUN npm run build +RUN npx vite build # ========== СТАДИЯ 2: СЕРВЕР ========== FROM nginx:alpine -- 2.54.0 From 8e7a687ab344cdb93a4f339a03ae65606348a67f Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Fri, 3 Apr 2026 13:37:11 +0300 Subject: [PATCH 11/53] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=D1=83=20http=20=D0=BD?= =?UTF-8?q?=D0=B0=20https?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/client.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/api/client.ts b/src/api/client.ts index 3989ee1..fa03c20 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -12,6 +12,17 @@ class ApiClient { }, }); + this.axiosInstance.interceptors.request.use( + (config) => { + if (config.baseURL && config.baseURL.startsWith('http://')) { + console.error('❌ Request uses HTTP instead of HTTPS:', config.baseURL); + config.baseURL = config.baseURL.replace('http://', 'https://'); + } + return config; + }, + (error) => Promise.reject(error) + ); + this.axiosInstance.interceptors.response.use( (response) => response, (error) => { -- 2.54.0 From e75023f15ae6479d2e4fa04ea5d9f7a0b642215c Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Sun, 5 Apr 2026 21:22:42 +0300 Subject: [PATCH 12/53] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B8=D1=80=D0=B5=D0=BA=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/client.ts | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/api/client.ts b/src/api/client.ts index fa03c20..6bd3591 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -10,18 +10,39 @@ class ApiClient { headers: { 'Content-Type': 'application/json', }, + maxRedirects: 0, + validateStatus: (status) => status >= 200 && status < 400, }); - this.axiosInstance.interceptors.request.use( - (config) => { - if (config.baseURL && config.baseURL.startsWith('http://')) { - console.error('❌ Request uses HTTP instead of HTTPS:', config.baseURL); - config.baseURL = config.baseURL.replace('http://', 'https://'); + this.axiosInstance.interceptors.response.use( + (response) => response, + async (error) => { + // Если это редирект (301, 302, 307, 308) + if (error.response && [301, 302, 307, 308].includes(error.response.status)) { + const location = error.response.headers.location; + console.log('🔄 Redirect detected:', location); + + if (location) { + // Исправляем HTTP на HTTPS + let fixedLocation = location; + if (fixedLocation.startsWith('http://')) { + fixedLocation = fixedLocation.replace('http://', 'https://'); + console.log('✅ Fixed URL:', fixedLocation); + } + + // Повторяем запрос на исправленный URL + try { + const response = await this.axiosInstance.get(fixedLocation); + return response; + } catch (retryError) { + return Promise.reject(retryError); + } + } } - return config; - }, - (error) => Promise.reject(error) + return Promise.reject(error); + } ); + this.axiosInstance.interceptors.response.use( (response) => response, -- 2.54.0 From 20afce31dd741063daaa5e7017d7684e0b5e67fd Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Sun, 5 Apr 2026 21:59:59 +0300 Subject: [PATCH 13/53] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20baseURL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/client.ts b/src/api/client.ts index 6bd3591..e0b27e3 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -3,7 +3,7 @@ import axios, { AxiosInstance } from 'axios'; class ApiClient { private axiosInstance: AxiosInstance; - constructor(baseURL: string = 'https://pvh.projects.rustprogersteam.ru') { + constructor(baseURL: string = 'https://pvh.projects.rustprogersteam.ru/api') { this.axiosInstance = axios.create({ baseURL, timeout: 10000, @@ -71,4 +71,4 @@ class ApiClient { } } -export const client = new ApiClient('https://pvh.projects.rustprogersteam.ru/api'); \ No newline at end of file +export const client = new ApiClient(); \ No newline at end of file -- 2.54.0 From d4f9aebf008a55a9f91202e676d08a8b3d999504 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Mon, 6 Apr 2026 21:18:00 +0300 Subject: [PATCH 14/53] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=B5=D0=B7=D0=B4=D0=B5=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ModalRequestForm/ModalRequestForm.tsx | 2 +- src/components/PriceLisForm/PriceLisForm.tsx | 2 +- src/features/MainPage/PhoneRequest.tsx | 2 +- src/features/catalog/categoriesSlice.ts | 2 +- src/features/catalog/productsSlice.ts | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ModalRequestForm/ModalRequestForm.tsx b/src/components/ModalRequestForm/ModalRequestForm.tsx index b6111d2..5d083cc 100644 --- a/src/components/ModalRequestForm/ModalRequestForm.tsx +++ b/src/components/ModalRequestForm/ModalRequestForm.tsx @@ -70,7 +70,7 @@ const ModalRequestForm: React.FC = ({ open, onClose }) => { ...data, }; - const response = await client.post<{ success: boolean }>("/email", payload); + const response = await client.post<{ success: boolean }>("/email/", payload); return response.data.success; } catch (error) { diff --git a/src/components/PriceLisForm/PriceLisForm.tsx b/src/components/PriceLisForm/PriceLisForm.tsx index 5771697..611d8e5 100644 --- a/src/components/PriceLisForm/PriceLisForm.tsx +++ b/src/components/PriceLisForm/PriceLisForm.tsx @@ -62,7 +62,7 @@ const PriceLisForm: React.FC = ({ open, onClose }) => { const sendToBackend = async (data: FormData): Promise => { try{ - const response = await client.post<{success: boolean}>("/email", { + const response = await client.post<{success: boolean}>("/email/", { ...data, }) diff --git a/src/features/MainPage/PhoneRequest.tsx b/src/features/MainPage/PhoneRequest.tsx index e35ef02..980d8d4 100644 --- a/src/features/MainPage/PhoneRequest.tsx +++ b/src/features/MainPage/PhoneRequest.tsx @@ -60,7 +60,7 @@ const PhoneRequest: React.FC = ({ onSend }) => { await onSend(phone); } else { - await client.post("/api/contact/send-phone", { phone }); + await client.post("/api/contact/send-phone/", { phone }); } setSuccess(true); diff --git a/src/features/catalog/categoriesSlice.ts b/src/features/catalog/categoriesSlice.ts index f1b8a81..9cbc651 100644 --- a/src/features/catalog/categoriesSlice.ts +++ b/src/features/catalog/categoriesSlice.ts @@ -5,7 +5,7 @@ import {client} from "../../api/client"; export const fetchCategories = createAsyncThunk( "categories/fetchCategories", async () => { - const res = await client.get("/categories"); + const res = await client.get("/categories/"); return res.data; } ); diff --git a/src/features/catalog/productsSlice.ts b/src/features/catalog/productsSlice.ts index 1126237..6130241 100644 --- a/src/features/catalog/productsSlice.ts +++ b/src/features/catalog/productsSlice.ts @@ -32,7 +32,7 @@ export const fetchProductsByCategory = createAsyncThunk( else qp.append(k, String(v)); }); } - const res = await client.get(`/products?${qp.toString()}`); + const res = await client.get(`/products?${qp.toString()}/`); // ожидаем { items: Product[], total: number, page: number, limit: number } return res.data; } @@ -41,7 +41,7 @@ export const fetchProductsByCategory = createAsyncThunk( export const fetchProductById = createAsyncThunk( "product/fetchById", async (id: string) => { - const response = await client.get(`/products/${id}`); + const response = await client.get(`/products/${id}/`); return response.data; } ); -- 2.54.0 From 524d9e3deb413d0e2f5e212641b82b96e0f663f7 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Tue, 7 Apr 2026 00:23:49 +0300 Subject: [PATCH 15/53] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=20=D0=BA=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B4=D1=83=D0=BA=D1=82=D0=B0=D0=BC=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D0=BA=D0=B0=D1=82=D0=B5=D0=B3=D0=BE=D1=80=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B0=D0=B6=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20=D0=BA=D0=B0=D1=80=D1=82=D0=BE=D1=87?= =?UTF-8?q?=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/catalog/CategoryCards.tsx | 19 +++++++++++++------ src/pages/Products/Products.tsx | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/features/catalog/CategoryCards.tsx b/src/features/catalog/CategoryCards.tsx index 22c3f0b..aef5d71 100644 --- a/src/features/catalog/CategoryCards.tsx +++ b/src/features/catalog/CategoryCards.tsx @@ -1,18 +1,25 @@ import React from "react"; import styles from "./Catalog.module.css"; -import { useAppSelector } from "../../app/hooks"; +import { useAppDispatch, useAppSelector } from "../../app/hooks"; +import { setSelectedCategory } from "./categoriesSlice"; +import { fetchProductsByCategory, setFilters, setPage } from "./productsSlice"; -interface Props { - onSelect?: (id:number) => void -} -const CategoryCards: React.FC = ({ onSelect }) => { +const CategoryCards: React.FC = () => { const categories = useAppSelector(s => s.categories.items); + const dispatch = useAppDispatch(); + + const onSelect = (catId:number) => { + dispatch(setSelectedCategory(catId)); + dispatch(setFilters({})); + dispatch(setPage(1)); + dispatch(fetchProductsByCategory({ categoryId: catId, page: 1, limit: 9 })); + } return (
{categories.map(c => ( -
onSelect?.(c.id)}> +
onSelect(c.id)}> {c.image ? {c.name} : {c.name}}
{c.name}
diff --git a/src/pages/Products/Products.tsx b/src/pages/Products/Products.tsx index 9961514..0be6057 100644 --- a/src/pages/Products/Products.tsx +++ b/src/pages/Products/Products.tsx @@ -15,7 +15,7 @@ const ProductsPage: React.FC = () => {
{!selectedCategoryId ? ( - {}} /> + ) : ( <>
-- 2.54.0 From 27523cb2a12595caa5898aee21d3b616db15c937 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Tue, 7 Apr 2026 15:18:09 +0300 Subject: [PATCH 16/53] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=B0=D0=B2=D0=B8=D0=B3=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Banner/Banner.tsx | 3 +++ src/components/Categories/Categories.tsx | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/Banner/Banner.tsx b/src/components/Banner/Banner.tsx index 652bb4b..68d49bf 100644 --- a/src/components/Banner/Banner.tsx +++ b/src/components/Banner/Banner.tsx @@ -4,6 +4,7 @@ import { Carousel } from "antd"; import Button from '../Button/Button.tsx'; import banner_img1 from '../../assets/images/mainPage/ChatGPT-Image-Oct-1_-2025_-05_29_18-PM.png' import banner_img2 from '../../assets/images/mainPage/296170994030930.jpg' +import { useNavigate } from 'react-router-dom'; export interface SlideItem { id: number; @@ -33,8 +34,10 @@ const slides: SlideItem[] = [ const BannerSlider: React.FC = () => { +const navigate = useNavigate(); const handleClick = () => { + navigate('/products') console.log('Кнопка нажата!'); }; diff --git a/src/components/Categories/Categories.tsx b/src/components/Categories/Categories.tsx index 2a72a39..25c29fe 100644 --- a/src/components/Categories/Categories.tsx +++ b/src/components/Categories/Categories.tsx @@ -4,6 +4,7 @@ import Button from "../Button/Button"; import category_internal1 from "../../assets/images/mainPage/category_internal1.jpg" import category_interna2 from "../../assets/images/mainPage/category_internal2.jpg" import { useAppSelector, useAppDispatch } from "../../app/hooks"; +import { useNavigate } from "react-router-dom"; interface CategoryItem { id: number; @@ -40,10 +41,12 @@ image: category_internal1, const CategoriesGrid: React.FC = () => { +const navigate = useNavigate(); const handleClick = () => { - console.log('Кнопка нажата!'); - }; + navigate('/products'); + console.log('Кнопка нажата!'); +}; return (
-- 2.54.0 From ba921e8348c3e8be705eed921f5572facc8f103d Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Tue, 7 Apr 2026 15:20:18 +0300 Subject: [PATCH 17/53] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BC=D0=BE=D0=B4=D0=B0=D0=BB=D0=BA=D1=83=20=D1=81=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B9=D1=81=D1=84=D0=BE=D1=80=D0=BC=D0=BE?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ContactProduct/ContactProduct.tsx | 2 +- src/components/ModalRequestForm/ModalRequestForm.tsx | 1 - src/pages/ItemPage/ItemPage.tsx | 11 ++++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/ContactProduct/ContactProduct.tsx b/src/components/ContactProduct/ContactProduct.tsx index 82a24e4..d50717f 100644 --- a/src/components/ContactProduct/ContactProduct.tsx +++ b/src/components/ContactProduct/ContactProduct.tsx @@ -40,7 +40,7 @@ const ProductionBanner: React.FC = () => { console.log('ProductionBanner render, open:', open); return ( -
+
setOpen(false)} />

КОНТРАКТНОЕ

diff --git a/src/components/ModalRequestForm/ModalRequestForm.tsx b/src/components/ModalRequestForm/ModalRequestForm.tsx index 5d083cc..ce42660 100644 --- a/src/components/ModalRequestForm/ModalRequestForm.tsx +++ b/src/components/ModalRequestForm/ModalRequestForm.tsx @@ -181,7 +181,6 @@ const ModalRequestForm: React.FC = ({ open, onClose }) => { +
-- 2.54.0 From 1cb9f9a509ae71eb5bbcbba5363accc4cc75ef4b Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Tue, 7 Apr 2026 15:43:53 +0300 Subject: [PATCH 18/53] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D1=83,=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PriceLisForm/PriceLisForm.module.css | 68 +++++++++++++++++++ src/components/PriceLisForm/PriceLisForm.tsx | 2 +- src/pages/ItemPage/ItemPage.tsx | 4 -- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/components/PriceLisForm/PriceLisForm.module.css b/src/components/PriceLisForm/PriceLisForm.module.css index e69de29..223bef9 100644 --- a/src/components/PriceLisForm/PriceLisForm.module.css +++ b/src/components/PriceLisForm/PriceLisForm.module.css @@ -0,0 +1,68 @@ +.modalBox { + padding: 10px 20px 30px; +} + +.title { + text-align: center; + font-size: 28px; + font-weight: 700; +} + +.subtitle { + text-align: center; + margin-top: 6px; + margin-bottom: 26px; + color: #666; + font-size: 16px; +} + +.form { + display: flex; + flex-direction: column; + gap: 16px; +} + +.field { + position: relative; +} + +.input { + width: 93%; + padding: 18px; + font-size: 18px; + border-radius: 12px; + border: 1px solid #ddd; + background: #f9f9f9; + outline: none; + transition: 0.2s; +} + +.input:focus { + border-color: #ffd400; + background: white; +} + +.textarea { + height: 120px; + resize: none; + padding: 18px; + border-radius: 12px; + border: 1px solid #ddd; + background: #f9f9f9; + font-size: 18px; +} + +.error { + font-size: 13px; + color: #d33; + position: absolute; + bottom: -18px; + left: 5px; +} + +.button { + margin-top: 10px; + width: 100%; + height: 58px; + font-size: 18px; +} \ No newline at end of file diff --git a/src/components/PriceLisForm/PriceLisForm.tsx b/src/components/PriceLisForm/PriceLisForm.tsx index 611d8e5..869cd94 100644 --- a/src/components/PriceLisForm/PriceLisForm.tsx +++ b/src/components/PriceLisForm/PriceLisForm.tsx @@ -4,7 +4,7 @@ import { motion } from "framer-motion"; import { useForm } from "react-hook-form"; import * as yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; -import styles from "./ModalRequestForm.module.css"; +import styles from "./PriceLisForm.module.css"; import Button from "../Button/Button"; import { client } from "../../api/client"; diff --git a/src/pages/ItemPage/ItemPage.tsx b/src/pages/ItemPage/ItemPage.tsx index aa14dea..c733a39 100644 --- a/src/pages/ItemPage/ItemPage.tsx +++ b/src/pages/ItemPage/ItemPage.tsx @@ -50,10 +50,6 @@ const ItemPage = () => {

{product.name}

{product.description}

- -
diff --git a/src/features/catalog/SidebarCategories.tsx b/src/features/catalog/SidebarCategories.tsx index 33eeae6..1e7cf65 100644 --- a/src/features/catalog/SidebarCategories.tsx +++ b/src/features/catalog/SidebarCategories.tsx @@ -25,7 +25,7 @@ const SidebarCategories: React.FC = () => {
    {items.map(cat => (
  • onClick(cat.id)}> {cat.name}
  • diff --git a/src/features/catalog/productsSlice.ts b/src/features/catalog/productsSlice.ts index 6130241..dd25eb0 100644 --- a/src/features/catalog/productsSlice.ts +++ b/src/features/catalog/productsSlice.ts @@ -54,6 +54,7 @@ interface ProductsState { loading: boolean; error: string | null; filtersApplied: Record; + selectedProductId: number | null; } const initialState: ProductsState = { @@ -64,12 +65,16 @@ const initialState: ProductsState = { loading: false, error: null, filtersApplied: {}, + selectedProductId: null }; const slice = createSlice({ name: "products", initialState, reducers: { + setSelectedProducts(state, action: PayloadAction){ + state.selectedProductId = action.payload; + }, setPage(state, action: PayloadAction) { state.page = action.payload; }, @@ -105,5 +110,5 @@ const slice = createSlice({ } }); -export const { setPage, setLimit, setFilters, resetProducts } = slice.actions; +export const { setPage, setLimit, setFilters, resetProducts, setSelectedProducts } = slice.actions; export default slice.reducer; \ No newline at end of file diff --git a/src/pages/ItemPage/ItemPage.module.css b/src/pages/ItemPage/ItemPage.module.css index e627a65..72830c2 100644 --- a/src/pages/ItemPage/ItemPage.module.css +++ b/src/pages/ItemPage/ItemPage.module.css @@ -6,6 +6,12 @@ .top { background: #000; padding: 15px 40px; + padding-top: 100px; +} + +.short{ + margin-top: 30px; + margin-bottom: 40px; } .back { @@ -33,15 +39,20 @@ max-width: 400px; } +.rightContent{ + padding-right: 100px; + +} + .right { flex: 1; background: linear-gradient( - rgba(0, 0, 0, 0.7), - rgba(0, 0, 0, 0.7) + rgba(44, 44, 44, 0.9), + rgba(44, 44, 44, 0.9) ), - url("/bg.jpg"); + url("../../assets/images/otkrytie-novogo-proizvodstva-v-g.Krymsk.jpeg"); color: white; - padding: 80px; + padding: 90px; display: flex; flex-direction: column; justify-content: center; diff --git a/src/pages/ItemPage/ItemPage.tsx b/src/pages/ItemPage/ItemPage.tsx index c733a39..0c905cd 100644 --- a/src/pages/ItemPage/ItemPage.tsx +++ b/src/pages/ItemPage/ItemPage.tsx @@ -6,6 +6,8 @@ import styles from "./ItemPage.module.css"; import type { CategoryAtributes, CategoryAtrVals } from "../../types/categories"; import Button from "../../components/Button/Button"; import PriceLisForm from "../../components/PriceLisForm/PriceLisForm"; +import ProductAttributes from "../../components/Table/ProducTable"; +import { p } from "framer-motion/client"; const ItemPage = () => { const { id } = useParams(); @@ -39,10 +41,11 @@ const ItemPage = () => {
    - {product.name} + {product.name}
    +
    ГЛАВНАЯ / {category?.name} / {product.name}
    @@ -54,6 +57,7 @@ const ItemPage = () => { label="СКАЧАТЬ ПРАЙС-ЛИСТ" onClick={() => setOpen(true)} /> +
    @@ -77,13 +81,21 @@ const ItemPage = () => {

    ОПИСАНИЕ

    {product.description}

    +

    {product.full_name}

    + {!product.inStock? + ( +

    в наличии

    + ) : ( +

    нет в наличии

    + ) + }
    )} {activeTab === "chars" && (

    ХАРАКТЕРИСТИКИ

    - {category.atributes?.map((attr: CategoryAtributes) => ( + {/*{product.attributes.map((attr) => (
    {attr.name} {attr.vals?.map((val: CategoryAtrVals) => ( @@ -92,7 +104,8 @@ const ItemPage = () => {
    ))}
    - ))} + ))}*/} +
)}
diff --git a/src/pages/Layout/Layout.tsx b/src/pages/Layout/Layout.tsx index 241d865..6788950 100644 --- a/src/pages/Layout/Layout.tsx +++ b/src/pages/Layout/Layout.tsx @@ -8,7 +8,7 @@ const Layout = () =>{ return( /*token ?*/
-
+
diff --git a/src/pages/Products/Products.module.css b/src/pages/Products/Products.module.css index e69de29..6bfd06c 100644 --- a/src/pages/Products/Products.module.css +++ b/src/pages/Products/Products.module.css @@ -0,0 +1,207 @@ +/* ===== ОБЩИЙ ЛЭЙАУТ ===== */ +.wrapper { + display: flex; + margin: 0; + justify-content: center; +} + +.container{ + display: flex; + background: #f3f3f3; + min-height: 100vh; + font-family: Arial, sans-serif; + width: 80%; +} + +/* ===== САЙДБАР ===== */ +.sidebar { + width: 280px; + background: #fff; + padding: 30px 20px; + border-right: 1px solid #e0e0e0; + + display: flex; + flex-direction: column; + padding-top: 70px; +} + +/* ===== ОСНОВНАЯ ЧАСТЬ ===== */ +.main { + flex: 1; + padding: 30px 40px; + padding-top: 100px; +} + +/* ===== ЛЭЙАУТ КАТАЛОГА ===== */ +.catalogLayout { + display: flex; + gap: 30px; + align-items: flex-start; +} + +/* ===== ФИЛЬТРЫ ===== */ +.filters { + width: 100%; /* 🔥 важно */ + border: 1px solid #e5e5e5; +} + +/* ===== БЛОК ТОВАРОВ ===== */ +.products { + flex: 1; + display: flex; + flex-direction: column; + gap: 25px; +} + +/* ===== GRID ===== */ +.grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + border-top: 1px solid #ddd; + border-left: 1px solid #ddd; +} + +/* ===== КАРТОЧКА ===== */ +.card { + background: #fff; + border-right: 1px solid #ddd; + border-bottom: 1px solid #ddd; + padding: 25px 20px; + text-align: center; + position: relative; + transition: all 0.2s ease; +} + +.card:hover { + box-shadow: 0 8px 20px rgba(0,0,0,0.08); +} + +/* ===== КАРТИНКА ===== */ +.card img { + max-height: 140px; + object-fit: contain; + margin-bottom: 15px; +} + +/* ===== НАЗВАНИЕ ===== */ +.card h3 { + font-size: 14px; + font-weight: 600; + color: #222; + min-height: 40px; +} + +/* ===== ПЛЮС КНОПКА ===== */ +.card::after { + content: "+"; + position: absolute; + right: 15px; + bottom: 15px; + color: #f5c400; + font-size: 22px; + font-weight: bold; +} + +/* ===== ПАГИНАЦИЯ ===== */ +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: 5px; +} + +.pageBtn { + width: 40px; + height: 40px; + border: 1px solid #ddd; + background: #fff; + cursor: pointer; + font-weight: 600; +} + +.pageBtn:hover { + background: #f5c400; +} + +.activePage { + background: #f5c400; + border-color: #f5c400; +} + +/* ===== ФИЛЬТРЫ СТИЛИ ===== */ +.filters h4 { + font-size: 14px; + margin-bottom: 10px; + margin-top: 20px; +} + +.filters label { + display: flex; + align-items: center; + gap: 8px; + font-size: 13px; + margin-bottom: 8px; + cursor: pointer; +} + +.filters input { + cursor: pointer; +} + +/* ===== КАТЕГОРИИ ===== */ +.sidebar h3 { + font-size: 16px; + margin-bottom: 20px; +} + +.sidebar ul { + list-style: none; + padding: 0; + margin: 0; +} + +.sidebar li { + font-size: 14px; + margin-bottom: 12px; + cursor: pointer; + color: #666; + transition: 0.2s; +} + +.sidebar li:hover { + color: #000; +} + +.activeCategory { + font-weight: 700; + color: #000; +} + +/* ===== АДАПТИВ ===== */ +@media (max-width: 1200px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .wrapper { + flex-direction: column; + } + + .sidebar { + width: 100%; + } + + .catalogLayout { + flex-direction: column; + } + + .filters { + width: 100%; + } + + .grid { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/src/pages/Products/Products.tsx b/src/pages/Products/Products.tsx index 0be6057..872543c 100644 --- a/src/pages/Products/Products.tsx +++ b/src/pages/Products/Products.tsx @@ -11,7 +11,7 @@ const ProductsPage: React.FC = () => { const { selectedCategoryId } = useAppSelector(s => s.categories); return ( -
+ /*
{!selectedCategoryId ? ( @@ -29,6 +29,27 @@ const ProductsPage: React.FC = () => { )}
+
*/ +
+
+ + +
+ {!selectedCategoryId ? ( + + ) : ( +
+ + +
+ )} +
+
); }; diff --git a/src/types/product.ts b/src/types/product.ts index eaf7d03..611728d 100644 --- a/src/types/product.ts +++ b/src/types/product.ts @@ -1,6 +1,12 @@ export interface Product { id: number; name: string; - image: string; description: string; + images: string[]; + inStock: boolean; + price: number | null; + attributes: Record; + categoryId?: number; + created_at: string; + full_name: string; } \ No newline at end of file -- 2.54.0 From b6f66ab4a70e03e146b68e88b674428c61e492b3 Mon Sep 17 00:00:00 2001 From: Oleg Urin Date: Thu, 9 Apr 2026 22:10:07 +0300 Subject: [PATCH 20/53] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D1=83=20=D1=81=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B2=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA=D1=83,=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D1=83=20=D0=B4=D0=BB=D1=8F=20=D0=B2=D0=BE=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 +- public/MiniLogo.jpg | Bin 0 -> 10967 bytes .../ModalRequestForm/ModalRequestForm.tsx | 2 +- .../QuestionsBlock/QuestionsBlock.tsx | 17 +- src/features/MainPage/PhoneRequest.tsx | 252 ++++++++++++------ 5 files changed, 180 insertions(+), 95 deletions(-) create mode 100644 public/MiniLogo.jpg diff --git a/index.html b/index.html index a6e9be0..4ae69d1 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,9 @@ - + - front + RK PLASTIC
diff --git a/public/MiniLogo.jpg b/public/MiniLogo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a964ca0de865e48485f526edb65dfb8a0282bcb GIT binary patch literal 10967 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 = ({ open, onClose }) => {