@@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -0,0 +1,5 @@ + + + + + @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + Binary files /dev/null and b/public/images/video.mp4 differ @@ -0,0 +1,43 @@ + + + + + + + + + + + + React App + + + +
+ + + @@ -0,0 +1,221 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useCart } from '../../hooks/UseCart.js'; +import CartItem from './CartItem.jsx'; +import CheckboxInput from './CheckboxInput.jsx'; +import SummaryRow from './SummaryRow.jsx'; +import styles from "./BasketMain.module.css"; +import toast from 'react-hot-toast'; + +export default function BasketMain() { + const navigate = useNavigate(); + const [agreements, setAgreements] = useState({ + newsletter: false, + personalData: false, + privacyPolicy: false + }); + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const { + cart, + removeFromCart, + updateQuantity, + clearCart, + calculateTotal, + calculateItemsCount + } = useCart(); + + useEffect(() => { + const loadUser = () => { + try { + const savedUser = localStorage.getItem('currentUser'); + if (savedUser) { + setUser(JSON.parse(savedUser)); + } else { + navigate('/login'); + } + } catch (error) { + navigate('/login'); + } finally { + setIsLoading(false); + } + }; + + loadUser(); + }, [navigate]); + + const handleAgreementChange = (name) => { + setAgreements(prev => ({ ...prev, [name]: !prev[name] })); + }; + + const handleCheckout = () => { + if (!agreements.personalData || !agreements.privacyPolicy) { + toast('Примите соглашения для оформления заказа'); + return; + } + + if (cart.length === 0) { + toast('Корзина пуста'); + return; + } + + const orderData = { + orderId: Date.now(), + userId: user?.id || user?.email, + userName: user?.fullName || user?.email, + items: cart, + totalAmount: calculateTotal(), + email: user?.email, + orderDate: new Date().toISOString(), + status: 'pending' + }; + + const existingOrders = JSON.parse(localStorage.getItem('orders') || '[]'); + localStorage.setItem('orders', JSON.stringify([...existingOrders, orderData])); + + toast(`Заказ #${orderData.orderId} оформлен на сумму $${calculateTotal()}`); + clearCart(); + navigate('/basket'); + }; + + if (isLoading) { + return ( +
+
+
+

Загрузка...

+
+
+ ); + } + + if (!user) { + return null; + } + + if (cart.length === 0) { + return ( +
+
+

Корзина пуста

+

+ Добавьте товары из каталога, чтобы сделать заказ +

+ +
+
+ ); + } + + return ( +
+
+
+

Корзина

+
+ Покупатель: {user.fullName || user.email} + Email: {user.email} +
+
+
+
+

+ Ваш заказ ({calculateItemsCount()} товаров) +

+
+ +
+ +
+ {cart.map(item => ( + updateQuantity(item.id, quantity)} + onRemove={() => removeFromCart(item.id)} + /> + ))} +
+ +
+

Сводка заказа

+
+ + + +
+
+ +
+

Соглашения

+ +
+ handleAgreementChange('newsletter')} + label="Получать рекламную информацию от prime" + /> + + handleAgreementChange('personalData')} + label="Я соглашаюсь с условиями обработки персональных данных" + required={true} + /> + + handleAgreementChange('privacyPolicy')} + label="Я соглашаюсь с политикой конфиденциальности" + required={true} + /> +
+ +

* Обязательные поля

+
+ +
+
+ К оплате: + ${calculateTotal().toLocaleString()} +
+ + +
+
+
+ ); +} \ No newline at end of file @@ -0,0 +1,696 @@ +.body { + min-height: 100vh; + background-color: #000000; + margin: 0; + padding: 0; +} + +.container { + font-family: "Orbitron", sans-serif; + max-width: 1200px; + margin: 0 auto; + padding: 20px; + display: grid; + gap: 20px; + min-height: 100vh; +} + +.loading { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 300px; +} + +.loadingSpinner { + width: 50px; + height: 50px; + border: 5px solid #f3f3f3; + border-top: 5px solid #3498db; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 20px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.userInfo { + background: rgb(0, 0, 0); + padding: 15px 20px; + border-radius: 8px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.userInfo span { + font-size: 14px; + color: #ffffff; +} + +.userInfo strong { + color: #ffffff; + margin-left: 5px; +} + +.title { + font-size: 32px; + font-weight: bold; + text-align: center; + margin-bottom: 30px; + color: #ffffff; +} + +.cartHeader { + font-family: "Orbitron", sans-serif; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 2px solid #e0e0e0; +} + +.cartTitle { + font-size: 20px; + font-weight: 600; + color: #ffffff; + margin: 0; +} + +.clearCartButton { + padding: 8px 16px; + background-color: #ff6b6b; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + transition: background-color 0.3s; +} + +.clearCartButton:hover { + background-color: #ff5252; +} + +.cartItems { + font-family: "Orbitron", sans-serif; + background: rgb(0, 0, 0); + border-radius: 10px; + padding: 20px; + margin-bottom: 30px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +.cartItem { + font-family: "Orbitron", sans-serif; + display: flex; + align-items: center; + padding: 15px 0; + border-bottom: 1px solid #f0f0f0; +} + +.cartItem:last-child { + border-bottom: none; +} + +.itemImage { + width: 100px; + height: 100px; + margin-right: 20px; + flex-shrink: 0; +} + +.itemImage img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px; +} + +.itemInfo { + flex: 1; + min-width: 0; +} + +.itemTitle { + font-family: "Orbitron", sans-serif; + font-size: 18px; + font-weight: 600; + margin: 0 0 10px 0; + color: #ffffff; + word-wrap: break-word; +} + +.itemDescription { + font-size: 14px; + color: #ffffff; + margin: 0 0 10px 0; + line-height: 1.4; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.itemPrice { + font-size: 16px; + font-weight: 600; + color: #4c77af; + display: block; + margin-bottom: 10px; +} + +.itemControls { + display: flex; + align-items: center; + gap: 20px; + flex-wrap: wrap; +} + +.quantityControl { + display: flex; + align-items: center; + gap: 10px; +} + +.quantityButton { + width: 30px; + height: 30px; + background: #000000; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 18px; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.3s; +} + +.quantityButton:hover { + background: #e0e0e0; +} + +.quantity { + font-size: 18px; + font-weight: 600; + min-width: 30px; + text-align: center; +} + +.itemTotal { + font-size: 20px; + font-weight: 700; + color: #ffffff; + min-width: 80px; + text-align: right; +} + +.removeButton { + width: 30px; + height: 30px; + background: #b0bce4; + color: white; + border: none; + border-radius: 50%; + cursor: pointer; + font-size: 18px; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.3s; +} + +.removeButton:hover { + background: #232c7e; +} + +.orderSummary { + background: white; + border-radius: 10px; + padding: 25px; + margin-bottom: 30px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +.summaryRow { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 0; + font-size: 16px; + color: #ffffff; +} + +.summaryDivider { + height: 1px; + background: #e0e0e0; + margin: 15px 0; +} + +.totalAmount { + font-size: 24px; + color: #0d1539; +} + +.agreementsSection { + background: white; + border-radius: 10px; + padding: 25px; + margin-bottom: 30px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +.agreementsTitle { + font-size: 20px; + font-weight: 600; + margin-bottom: 20px; + color: #ffffff; +} + +.agreementItem { + margin-bottom: 15px; +} + +.checkboxLabel { + display: flex; + align-items: flex-start; + gap: 10px; + font-size: 16px; + color: #fffdfd; + cursor: pointer; + line-height: 1.4; +} + +.checkbox { + width: 18px; + height: 18px; + cursor: pointer; + accent-color: #121f56; + margin-top: 3px; + flex-shrink: 0; +} + +.requiredNote { + font-size: 14px; + color: #ffffff; + margin-top: 15px; + font-style: italic; + display: flex; + padding-bottom: 20px; +} + +.checkout { + border-radius: 10px; + padding: 25px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 3rem; + background: rgb(0, 0, 0); +} + +.checkboxContainer { + display: flex; + align-items: center; + width: 100%; + padding-bottom: 20px; + border-bottom: 2px solid #e0e0e0; + gap: 20px; + flex-wrap: wrap; +} + +.checkoutTotal { + font-size: 20px; + font-weight: 600; + color: #ffffff; + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.checkoutTotalAmount { + font-size: 32px; + font-weight: 800; + color: #2b239c; +} + +.checkoutButton { + padding: 16px 40px; + background: #2b239c; + color: white; + border: none; + border-radius: 8px; + font-size: 18px; + font-weight: 700; + cursor: pointer; + width: 100%; + max-width: 400px; + transition: all 0.3s; + white-space: nowrap; +} + +.checkoutButton:hover:not(:disabled) { + background: #2b239c; + transform: translateY(-2px); + box-shadow: 0 4px 15px rgba(43, 35, 156, 0.3); +} + +.checkoutButton:disabled { + background: #cccccc; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +.continueShoppingLink { + color: #2196F3; + text-decoration: none; + font-size: 16px; + transition: color 0.2s; +} + +.continueShoppingLink:hover { + color: #0b7dda; + text-decoration: underline; +} + +.emptyCart { + font-family: "Orbitron", sans-serif; + text-align: center; + padding: 60px 20px; + max-width: 500px; + margin: 0 auto; + padding-top: 30vh; +} + +.emptyCartIcon { + font-size: 80px; + margin-bottom: 20px; + opacity: 0.3; +} + +.emptyCartTitle { + font-size: 28px; + font-weight: 600; + margin-bottom: 15px; + color: #ffffff; +} + +.emptyCartText { + font-size: 16px; + color: #ffffff; + margin-bottom: 30px; + line-height: 1.5; +} + +.continueShopping { + display: inline-block; + padding: 12px 30px; + background: #2196F3; + color: white; + text-decoration: none; + border-radius: 6px; + font-weight: 600; + transition: background 0.3s; +} + +.continueShopping:hover { + background: #0b7dda; +} + + +@media (min-width: 1440px) { + .container { + max-width: 1400px; + padding: 40px; + } + + .title { + font-size: 36px; + } +} + +@media (max-width: 1199px) { + .container { + max-width: 100%; + padding: 20px; + } + + .cartItem { + flex-wrap: wrap; + } + + .itemInfo { + flex-basis: calc(100% - 120px); + } +} + +@media (max-width: 1023px) { + .title { + font-size: 28px; + margin-bottom: 20px; + } + + .cartHeader { + flex-direction: column; + align-items: flex-start; + gap: 15px; + } + + .cartItem { + flex-direction: column; + align-items: flex-start; + gap: 15px; + } + + .itemImage { + width: 100%; + height: 200px; + margin-right: 0; + } + + .itemControls { + width: 100%; + justify-content: space-between; + } + + .checkout { + flex-direction: column; + gap: 20px; + align-items: stretch; + } + + .checkoutTotal { + justify-content: space-between; + } + + .checkoutButton { + max-width: 100%; + } + + .emptyCart { + padding-top: 20vh; + } +} + +@media (max-width: 767px) { + .container { + padding: 15px; + gap: 15px; + } + + .title { + font-size: 24px; + } + + .userInfo { + flex-direction: column; + gap: 10px; + padding: 15px; + } + + .cartTitle { + font-size: 18px; + } + + .cartItems, + .orderSummary, + .agreementsSection, + .checkout { + padding: 15px; + } + + .itemTitle { + font-size: 16px; + } + + .itemPrice, + .itemTotal { + font-size: 16px; + } + + .summaryRow { + font-size: 14px; + } + + .totalAmount { + font-size: 20px; + } + + .agreementsTitle { + font-size: 18px; + } + + .checkboxLabel { + font-size: 14px; + } + + .checkoutTotal { + flex-direction: column; + gap: 10px; + text-align: center; + } + + .checkoutTotalAmount { + font-size: 28px; + } + + .checkoutButton { + padding: 14px 20px; + font-size: 16px; + } + + .emptyCartTitle { + font-size: 22px; + } + + .emptyCartIcon { + font-size: 60px; + } +} + +@media (max-width: 575px) { + .container { + padding: 10px; + gap: 10px; + } + + .title { + font-size: 20px; + margin-bottom: 15px; + } + + .cartHeader { + gap: 10px; + } + + .clearCartButton { + padding: 6px 12px; + font-size: 13px; + } + + .itemDescription { + -webkit-line-clamp: 3; + } + + .itemControls { + flex-direction: column; + align-items: flex-start; + gap: 15px; + } + + .quantityControl { + width: 100%; + justify-content: space-between; + } + + .removeButton { + align-self: flex-end; + } + + .checkboxContainer { + flex-direction: column; + align-items: flex-start; + gap: 15px; + } + + .checkoutTotal { + width: 100%; + } + + .emptyCart { + padding: 40px 15px; + padding-top: 15vh; + } + + .emptyCartTitle { + font-size: 20px; + } + + .emptyCartText { + font-size: 14px; + } + + .continueShopping { + padding: 10px 20px; + font-size: 14px; + } +} + +@media (max-width: 320px) { + .container { + padding: 8px; + } + + .title { + font-size: 18px; + } + + .cartTitle { + font-size: 16px; + } + + .itemImage { + height: 150px; + } + + .checkoutTotalAmount { + font-size: 24px; + } + + .checkoutButton { + font-size: 14px; + padding: 12px 16px; + } +} + +@media (max-width: 1440px) and (min-width: 1200px) { + .container { + max-width: 1100px; + } +} + +@media (max-width: 767px) { + .body { + overflow-x: hidden; + } + + .container { + overflow-x: hidden; + } + + img { + max-width: 100%; + height: auto; + } +} + @@ -0,0 +1,39 @@ +import styles from "./BasketMain.module.css"; + +export default function CartItem({ item, onRemove }){ + return ( +
+
+ {item.title} { + e.target.src = 'https://via.placeholder.com/150x150?text=No+Image'; + }} + /> +
+
+

{item.title}

+

{item.description}

+
Цена: ${item.price}
+
+
+
+ {item.quantity} +
+
+ ${(item.price * item.quantity).toLocaleString()} +
+ +
+
+ ); +}; \ No newline at end of file @@ -0,0 +1,30 @@ +import styles from './BasketMain.module.css'; +export default function CheckboxInput({ + id, + name, + checked, + onChange, + label, + required = false, + className = '', + ...props +}) { + return ( +
+ + +
+ ); +} \ No newline at end of file @@ -0,0 +1,74 @@ +import { useState, useEffect } from 'react'; +import styles from './BasketMain.module.css'; + +export default function QuantityControl({ + quantity, + onChange, + min = 1, + max = 99, + className = '' +}) { + const [localQuantity, setLocalQuantity] = useState(quantity); + + useEffect(() => { + setLocalQuantity(quantity); + }, [quantity]); + + const handleIncrement = () => { + if (localQuantity < max) { + const newQuantity = localQuantity + 1; + setLocalQuantity(newQuantity); + onChange(newQuantity); + } + }; + + const handleDecrement = () => { + if (localQuantity > min) { + const newQuantity = localQuantity - 1; + setLocalQuantity(newQuantity); + onChange(newQuantity); + } + }; + + const handleManualChange = (e) => { + const value = parseInt(e.target.value); + if (!isNaN(value) && value >= min && value <= max) { + setLocalQuantity(value); + onChange(value); + } + }; + + return ( +
+ + + + + +
+ ); +} \ No newline at end of file @@ -0,0 +1,20 @@ +import styles from './BasketMain.module.css'; + +export default function SummaryRow({ + label, + value, + isTotal = false, + isDiscount = false, + className = '' +}) { + return ( +
+ + {label} + + + {value} + +
+ ); +} \ No newline at end of file @@ -0,0 +1,210 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import styles from "./Profile.module.css"; + +export default function DataProfile() { + const navigate = useNavigate(); + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isEditing, setIsEditing] = useState(false); + const [editForm, setEditForm] = useState({ + fullName: '', + phone: '', + email: '' + }); + + useEffect(() => { + const loadUserData = () => { + setIsLoading(true); + try { + const savedUser = localStorage.getItem('currentUser'); + if (savedUser) { + const userData = JSON.parse(savedUser); + setUser(userData); + setEditForm({ + fullName: userData.fullName || '', + phone: userData.phone || '', + email: userData.email || '' + }); + } else { + navigate('/login'); + } + } catch (error) { + console.error('Ошибка загрузки данных пользователя:', error); + } finally { + setIsLoading(false); + } + }; + + loadUserData(); + }, [navigate]); + + const handleEdit = () => { + setIsEditing(true); + }; + + const handleCancelEdit = () => { + setIsEditing(false); + setEditForm({ + fullName: user.fullName || '', + phone: user.phone || '', + email: user.email || '' + }); + }; + + const handleSave = () => { + if (!editForm.fullName.trim() || !editForm.phone.trim() || !editForm.email.trim()) { + alert('Все поля обязательны для заполнения'); + return; + } + + const updatedUser = { + ...user, + ...editForm + }; + + setUser(updatedUser); + localStorage.setItem('currentUser', JSON.stringify(updatedUser)); + + const users = JSON.parse(localStorage.getItem('registeredUsers') || '[]'); + const updatedUsers = users.map(u => + u.email === user.email ? updatedUser : u + ); + localStorage.setItem('registeredUsers', JSON.stringify(updatedUsers)); + + setIsEditing(false); + alert('Данные успешно обновлены!'); + }; + + const handleLogout = () => { + localStorage.removeItem('currentUser'); + navigate('/login'); + }; + + const handleInputChange = (e) => { + const { name, value } = e.target; + setEditForm(prev => ({ + ...prev, + [name]: value + })); + }; + + if (isLoading) { + return ( +
+
Загрузка профиля...
+
+ ); + } + + if (!user) { + return null; + } + + return ( +
+ +
+ + + +
+ +
+ + +

{user.fullName}

+

{user.email}

+
+ +
+

Личная информация

+ + {isEditing ? ( +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ ) : ( + <> +
+ ФИО: + {user.fullName} +
+ +
+ Email: + {user.email} +
+ +
+ Телефон: + {user.phone} +
+ +
+ Дата регистрации: + + {user.registeredAt ? new Date(user.registeredAt).toLocaleDateString('ru-RU') : 'Не указана'} + +
+ +
+ + +
+ + )} +
+
+
+
+ + ); +} \ No newline at end of file @@ -0,0 +1,585 @@ +.body { + min-height: 100vh; + background-color: #000000; + margin: 0; + padding: 0; + overflow-x: hidden; +} + +.profileContainer { + font-family: "Orbitron", sans-serif; + display: grid; + width: 100%; + max-width: 800px; + margin: 0 auto; + padding: 20px; + box-sizing: border-box; + margin-top: 10rem; + padding-bottom: 7rem; +} + +.profileTitle { + font-size: 2rem; + font-weight: bold; + text-align: center; + color: #333; + margin-bottom: 2rem; +} + +.profileInfo { + background: rgb(86, 89, 100); + border-radius: 12px; + padding: 2rem; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + width: 100%; + box-sizing: border-box; +} + +.avatarSection { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + margin-bottom: 2rem; + padding-bottom: 2rem; + border-bottom: 1px solid #eee; +} + +.avatar { + width: 150px; + height: 150px; + border-radius: 50%; + object-fit: cover; + margin: 0 auto 1.5rem; + display: block; + border: 4px solid #667eea; +} + +.userName { + font-size: 1.8rem; + font-weight: bold; + margin-bottom: 0.5rem; + color: #f0f0f0; +} + +.userEmail { + font-size: 1rem; + color: #cccccc; + margin-bottom: 0; +} + +.infoSection { + width: 100%; + margin-top: 2rem; +} + +.sectionTitle { + font-size: 1.5rem; + font-weight: 600; + margin-bottom: 1.5rem; + color: #f0f0f0; + padding-bottom: 1rem; + border-bottom: 2px solid #555; +} + +.infoRow { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #666; +} + +.infoRow:last-child { + border-bottom: none; +} + +.infoLabel { + font-weight: 500; + color: #cccccc; + min-width: 120px; +} + +.infoValue { + font-weight: 400; + color: #ffffff; + text-align: right; + flex: 1; + word-break: break-word; +} + +.editForm { + background: #1f1f1f; + padding: 1.5rem; + border-radius: 8px; + border: 1px solid #e0e0e0; + margin-top: 1rem; +} + +.formGroup { + margin-bottom: 1.5rem; +} + +.label { + display: block; + margin-bottom: 8px; + font-weight: 500; + color: #f8f8f8; +} + +.editInput { + width: 100%; + padding: 0.75rem 1rem; + border: 1px solid #ddd; + border-radius: 6px; + font-size: 1rem; + transition: border-color 0.3s; + box-sizing: border-box; + background-color: #6d6d6d; +} + +.editInput:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +} + +.editButtons { + display: flex; + gap: 1rem; + margin-top: 1.5rem; + flex-wrap: wrap; +} + +.saveButton { + padding: 12px 24px; + background: #667eea; + color: white; + border: none; + border-radius: 6px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; + flex: 1; + min-width: 120px; +} + +.saveButton:hover { + transform: translateY(-2px); + background: #5a6fd8; +} + +.cancelButton { + padding: 12px 24px; + background: #f0f0f0; + color: #666; + border: none; + border-radius: 6px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; + flex: 1; + min-width: 120px; +} + +.cancelButton:hover { + background: #e0e0e0; +} + +.actionButtons { + display: flex; + gap: 1rem; + margin-top: 2rem; + flex-wrap: wrap; +} + +.editButton { + padding: 12px 24px; + background: #667eea; + color: white; + border: none; + border-radius: 6px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; + flex: 1; + min-width: 120px; +} + +.editButton:hover { + background: #5a6fd8; + transform: translateY(-2px); +} + +.logoutButton { + padding: 12px 24px; + background: #1f1a1a; + color: white; + border: none; + border-radius: 6px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; + flex: 1; + min-width: 120px; +} + +.logoutButton:hover { + background: #ff5252; + transform: translateY(-2px); +} + +.fon { + margin-top: 2rem; + text-align: center; +} + + +@media (min-width: 1440px) { + .profileContainer { + max-width: 1400px; + padding: 40px; + } + + .profileTitle { + font-size: 2.5rem; + } + + .profileInfo { + padding: 3rem; + } +} + +@media (max-width: 1199px) { + .profileContainer { + max-width: 100%; + padding: 30px; + } + + .avatar { + width: 140px; + height: 140px; + } +} + +@media (max-width: 1023px) { + .profileContainer { + padding: 20px; + margin-top: 5rem; + } + + .profileTitle { + font-size: 1.8rem; + margin-bottom: 1.5rem; + } + + .profileInfo { + padding: 1.5rem; + } + + .avatar { + width: 130px; + height: 130px; + } + + .userName { + font-size: 1.6rem; + } + + .sectionTitle { + font-size: 1.3rem; + } + + .infoRow { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + + .infoValue { + text-align: left; + width: 100%; + } + + .actionButtons, + .editButtons { + flex-direction: column; + } + + .saveButton, + .cancelButton, + .editButton, + .logoutButton { + width: 100%; + max-width: 300px; + margin: 0 auto; + } +} + +@media (max-width: 767px) { + .profileContainer { + padding: 15px; + margin-top: 4rem; + } + + .profileTitle { + font-size: 1.6rem; + margin-bottom: 1rem; + } + + .profileInfo { + padding: 1rem; + border-radius: 8px; + } + + .avatar { + width: 120px; + height: 120px; + } + + .userName { + font-size: 1.4rem; + } + + .userEmail { + font-size: 0.9rem; + } + + .sectionTitle { + font-size: 1.2rem; + margin-bottom: 1rem; + } + + .infoLabel { + font-size: 0.9rem; + min-width: 100px; + } + + .infoValue { + font-size: 0.9rem; + } + + .editForm { + padding: 1rem; + } + + .label { + font-size: 0.9rem; + } + + .editInput { + padding: 0.6rem 0.8rem; + font-size: 0.9rem; + } + + .saveButton, + .cancelButton, + .editButton, + .logoutButton { + padding: 10px 20px; + font-size: 14px; + } +} + +@media (max-width: 575px) { + .profileContainer { + padding: 10px; + margin-top: 3rem; + } + + .profileTitle { + font-size: 1.4rem; + } + + .profileInfo { + padding: 0.8rem; + border-radius: 6px; + } + + .avatarSection { + margin-bottom: 1.5rem; + padding-bottom: 1.5rem; + } + + .avatar { + width: 100px; + height: 100px; + margin-bottom: 1rem; + } + + .userName { + font-size: 1.2rem; + } + + .userEmail { + font-size: 0.85rem; + } + + .infoSection { + margin-top: 1.5rem; + } + + .sectionTitle { + font-size: 1.1rem; + padding-bottom: 0.8rem; + margin-bottom: 0.8rem; + } + + .infoRow { + padding: 8px 0; + } + + .infoLabel { + font-size: 0.85rem; + min-width: 80px; + } + + .infoValue { + font-size: 0.85rem; + } + + .editForm { + padding: 0.8rem; + } + + .formGroup { + margin-bottom: 1rem; + } + + .label { + font-size: 0.85rem; + margin-bottom: 6px; + } + + .editInput { + padding: 0.5rem 0.7rem; + font-size: 0.85rem; + } + + .editButtons { + margin-top: 1rem; + gap: 0.5rem; + } + + .actionButtons { + margin-top: 1.5rem; + gap: 0.5rem; + } + + .saveButton, + .cancelButton, + .editButton, + .logoutButton { + padding: 8px 16px; + font-size: 13px; + min-width: 100px; + } +} + +@media (max-width: 320px) { + .profileContainer { + padding: 8px; + margin-top: 2rem; + } + + .profileTitle { + font-size: 1.2rem; + } + + .profileInfo { + padding: 0.6rem; + } + + .avatar { + width: 80px; + height: 80px; + } + + .userName { + font-size: 1rem; + } + + .sectionTitle { + font-size: 1rem; + } + + .infoLabel { + font-size: 0.8rem; + min-width: 70px; + } + + .infoValue { + font-size: 0.8rem; + } + + .saveButton, + .cancelButton, + .editButton, + .logoutButton { + padding: 6px 12px; + font-size: 12px; + } +} + +@media (prefers-color-scheme: dark) { + .profileInfo { + background: #2d2d2d; + } + + .userName, + .sectionTitle { + color: #ffffff; + } + + .userEmail, + .infoLabel { + color: #cccccc; + } + + .infoValue { + color: #ffffff; + } + + .infoRow { + border-bottom-color: #444; + } + + .sectionTitle { + border-bottom-color: #444; + } +} + +@media (max-height: 600px) and (orientation: portrait) { + .profileContainer { + margin-top: 2rem; + } + + .avatarSection { + margin-bottom: 1rem; + padding-bottom: 1rem; + } + + .avatar { + width: 80px; + height: 80px; + } + + .userName { + font-size: 1.2rem; + } +} + +* { + box-sizing: border-box; +} + +button, +input { + transition: all 0.3s ease; +} + + @@ -0,0 +1,52 @@ +import styles from './Footer.module.css'; +import { Link } from 'react-router-dom'; +import { footer } from '../constants'; + +export default function Footer() { + const renderLink = (link) => { + if (link.external) { + return ( + + {link.title} + + ); + } + + return ( + + {link.title} + + ); + }; + + return ( + + ); +} \ No newline at end of file @@ -0,0 +1,52 @@ + +.hrr{ + border-top: 3px solid rgb(255, 255, 255); + padding-bottom: 3rem; +} +.logo { + font-family: "Orbitron", sans-serif; + font-optical-sizing: auto; + font-weight: weight; + font-style: normal; + font-size: 2.25rem; + color: #ffffff; + margin-top: 4.375rem; + margin-left: 8.0625rem; +} +.link{ + display: grid; + width: auto; + font-family: "Didact Gothic", sans-serif; + font-size: 1rem; + color: #ffffff; + margin-top: 3.125rem; + margin-left: 18.31rem; + text-decoration: none; +} +.linkSocial{ + display: grid; + gap: 1rem; + width: auto; + font-family: "Didact Gothic", sans-serif; + font-size: 1rem; + color: #ffffff; + margin-top: 3.125rem; + text-decoration: none; + padding-right: 7rem; +} +a{ + color: #ffffff; + text-decoration: none; +} +.linkItem{ + text-decoration: none; + color: #ffffff; +} +.linksContainer{ + justify-content: space-between; + display: flex; + padding-bottom: 2rem; +} +.footer{ + background-color: black; +} \ No newline at end of file @@ -0,0 +1,71 @@ +import { Link } from 'react-router-dom'; +import { useAuth } from '../../hooks/UseAuth'; +import styles from './Header.module.css'; +import { guestNavItems } from '../constants'; +import { authNavItems } from '../constants'; + + +export default function Header() { +const { isAuthenticated, isLoading } = useAuth(false); + + const navItems = isAuthenticated ? authNavItems : guestNavItems; + + const handleItemClick = (item, e) => { + if (item.isAction && item.action) { + e.preventDefault(); + item.action(); + } + }; + + if (isLoading) { + return ( +
+ prime +
+ Загрузка меню... +
+
+ ); + } + + return ( +
+ prime + +
+ ); +} \ No newline at end of file @@ -0,0 +1,472 @@ +.menuimg { + width: 3rem; + height: auto; + cursor: pointer; + transition: transform 0.3s ease; +} + +.menuimg:hover { + transform: scale(1.1); +} + +header { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + margin: 0 auto; + padding: 1.5rem 20px; + box-sizing: border-box; + position: absolute; + justify-content: space-between; + padding-left: 8rem; + padding-right: 8rem; +} + +.logo { + font-family: "Orbitron", sans-serif; + font-size: 2rem; + color: #ffffff; + margin: 0; + z-index: 1000; +} + +.select { + width: auto; + cursor: pointer; + position: relative; + transition: all 0.3s ease; + color: rgb(218, 218, 218); + overflow: visible; + z-index: 1000; +} + +.selected { + font-family: "Didact Gothic", sans-serif; + background-color: rgb(0, 0, 0); + padding: 0.75rem 1rem; + border-radius: 8px; + position: relative; + z-index: 1002; + font-size: 0.9rem; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + backdrop-filter: blur(10px); + border: 1px solid rgb(0, 0, 0); + min-width: 3.5rem; + min-height: 3.5rem; +} + +.selected:hover { + background-color:rgb(0, 0, 0); +} + +.arrow { + position: relative; + height: 10px; + transform: rotate(-90deg); + width: 1rem; + fill: rgb(176, 176, 176); + z-index: 1000; + transition: transform 0.3s ease; +} + +.options { + display: flex; + flex-direction: column; + border-radius: 8px; + padding: 0.5rem; + background-color:rgb(0, 0, 0); + position: absolute; + top: 100%; + right: 0; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: all 0.3s ease; + font-family: "Orbitron", sans-serif; + min-width: 12rem; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); + z-index: 1001; +} + +.select:hover .options, +.select:focus-within .options { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.select:hover .selected .arrow, +.select:focus-within .selected .arrow { + transform: rotate(0deg); +} + +.option { + border-radius: 6px; + padding: 0.75rem 1rem; + transition: all 0.2s ease; + background-color: transparent; + font-size: 0.9rem; + text-align: left; + cursor: pointer; + text-decoration: none; + display: block; + color: #ffffffb3; +} + +.option:hover { + background-color: rgb(0, 0, 0); + color: #ffffff; + transform: translateX(5px); +} + +.options input[type="radio"] { + display: none; +} + +.options label { + display: inline-block; + cursor: pointer; + text-decoration: none; + color: inherit; + width: 100%; +} + +.options label::before { + content: attr(data-txt); + cursor: pointer; + text-decoration: none; +} + +.options input[type="radio"]:checked + label { + display: none; +} + +.options input[type="radio"]#all:checked + label { + display: none; +} + +a { + cursor: pointer; + text-decoration: none; + color: inherit; +} + +.mobileMenuToggle { + display: none; + background: none; + border: none; + cursor: pointer; + padding: 0.5rem; + z-index: 1003; +} + +.mobileMenuIcon { + width: 2rem; + height: 2rem; + fill: #ffffff; +} + + +@media (min-width: 1440px) { + + .logo { + font-size: 2rem; + } + + .menuimg { + width: 4rem; + } + + .selected { + padding: 1rem 1.25rem; + font-size: 1rem; + } + + .options { + min-width: 14rem; + } + + .option { + padding: 1rem 1.25rem; + font-size: 1rem; + } +} + +@media (max-width: 1199px) { + + .logo { + font-size: 1.25rem; + } + + .menuimg { + width: 3.5rem; + } + + .selected { + padding: 0.625rem 0.875rem; + } + + .options { + min-width: 11rem; + } +} + +@media (max-width: 1023px) { + + .logo { + font-size: 1.1rem; + } + + .menuimg { + width: 3rem; + } + + .select { + margin-left: 0; + } + + .selected { + padding: 0.5rem 0.75rem; + min-width: 3rem; + min-height: 3rem; + } + + .arrow { + display: none; + } + + .options { + right: -50%; + transform: translateX(-50%) translateY(-10px); + } + + .select:hover .options, + .select:focus-within .options { + transform: translateX(-50%) translateY(0); + } +} + +@media (max-width: 767px) { + + .logo { + font-size: 1rem; + } + + .menuimg { + width: 2.5rem; + } + + .selected { + padding: 0.4rem 0.6rem; + font-size: 0.8rem; + min-width: 2.5rem; + min-height: 2.5rem; + } + + .options { + min-width: 10rem; + right: -70%; + } + + .option { + padding: 0.625rem 0.75rem; + font-size: 0.85rem; + } + + .mobileMenuToggle { + display: block; + } + + .select { + position: fixed; + top: 1rem; + right: 1rem; + } + + .options { + position: fixed; + top: 4rem; + right: 1rem; + left: 1rem; + min-width: auto; + max-width: 300px; + margin: 0 auto; + } +} + +@media (max-width: 575px) { + + .logo { + font-size: 0.9rem; + } + + .menuimg { + width: 2rem; + } + + .selected { + padding: 0.3rem 0.5rem; + min-width: 2rem; + min-height: 2rem; + } + + .selected span { + display: none; + } + + .options { + position: fixed; + top: 3.5rem; + right: 0.5rem; + left: 0.5rem; + max-width: 250px; + } + + .option { + padding: 0.5rem 0.625rem; + font-size: 0.8rem; + } +} + +@media (max-width: 320px) { + + .logo { + font-size: 0.8rem; + } + + .menuimg { + width: 1.75rem; + } + + .selected { + padding: 0.25rem 0.4rem; + min-width: 1.75rem; + min-height: 1.75rem; + } + + .options { + top: 3rem; + right: 0.25rem; + left: 0.25rem; + max-width: 200px; + } + + .option { + padding: 0.4rem 0.5rem; + font-size: 0.75rem; + } +} + +@media (max-height: 600px) and (orientation: portrait) { + .options { + max-height: 300px; + overflow-y: auto; + } +} + +@media (min-width: 768px) and (max-width: 1023px) and (orientation: landscape) { + .options { + right: 0; + transform: translateY(-10px); + } + + .select:hover .options, + .select:focus-within .options { + transform: translateY(0); + } +} + +@media (prefers-color-scheme: dark) { + .selected { + background-color: rgba(20, 20, 20, 0.9); + } + + .options { + background-color: rgba(20, 20, 20, 0.95); + } + + .option:hover { + background-color: rgba(40, 45, 55, 0.5); + } +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.options { + animation: fadeIn 0.3s ease forwards; +} + +.selected:focus, +.option:focus { + outline: 2px solid #667eea; + outline-offset: 2px; +} + +@media (prefers-reduced-motion: reduce) { + .menuimg, + .selected, + .options, + .option, + .arrow { + transition: none; + } + + .options { + animation: none; + } +} + +@supports (-webkit-touch-callout: none) { + .selected { + -webkit-tap-highlight-color: transparent; + } + + .option { + -webkit-tap-highlight-color: rgba(255, 255, 255, 0.1); + } +} + +.loadingMenu { + font-family: "Didact Gothic", sans-serif; + font-size: 0.9rem; + color: rgba(255, 255, 255, 0.7); + padding: 1rem; + text-align: center; +} + +.authStatus { + font-size: 0.8rem; + margin-left: 0.5rem; + opacity: 0.7; +} + +.menuItemWrapper { + width: 100%; +} + +.menuLink { + display: block; + width: 100%; + text-decoration: none; + color: inherit; + cursor: pointer; +} + +.menuLink:hover { + background-color: inherit; +} @@ -0,0 +1,14 @@ +import styles from './MainButton.module.css' +import { Link } from 'react-router-dom'; +import { Icon } from './icon.js'; + +export default function MainButton() { + return ( + + + + ); +} @@ -0,0 +1,67 @@ + +.cssbuttonsIoButton { + font-family: "Orbitron", sans-serif; + background: #ebebeb; + color: rgb(0, 0, 0); + padding: 0.35em; + padding-left: 3.5rem; + font-size: 17px; + font-weight: 600; + border-radius: 0.25rem; + border: none; + letter-spacing: 0.05em; + display: flex; + align-items: center; + box-shadow: inset 0 0 1.6em -0.6em #ffffff; + overflow: hidden; + position: relative; + height: 2.8em; + padding-right: 8rem; + cursor: pointer; +} + + .icon{ + background: #a2b8d9; + position: absolute; + display: flex; + align-items: center; + justify-content: center; + height: 2.5em; + width: 2.5em; + border-radius: 0.25rem; + box-shadow: 0.1em 0.1em 0.6em 0.1em #ffffff; + right: 0.3em; + transition: all 0.3s; +} + + +.cssbuttonsIoButton:hover .icon { + width: calc(100% - 0.6em); +} + +.cssbuttonsIoButton .icon svg { + width: 1.1em; + transition: transform 0.3s; + color: #ffffff; +} + +.cssbuttonsIoButton:hover .icon svg { + transform: translateX(0.1em); +} + +.cssbuttonsIoButton:active .icon { + transform: scale(0.95); +} +a { + cursor: pointer; + text-decoration: none; +} + +a:visited { + color: inherit; +} +.a { + position: absolute; + margin-top: 15rem; + margin-left: 8.0625rem; +} @@ -0,0 +1,23 @@ +import React from 'react'; +import styles from './MainButton.module.css' + + +export const Icon = ({ +}) => { + return ( +
+ + + + +
+ ); +}; @@ -0,0 +1,50 @@ +import { useState } from "react"; +import styles from './Slider.module.css' +import { slides } from '../constants'; + +export default function FunctionSlide() { + + const [currentSlide, setCurrentSlide] = useState(0); + + const nextSlide = () => { + setCurrentSlide((prev) => (prev === slides.length - 1 ? 0 : prev + 1)); + }; + + const prevSlide = () => { + setCurrentSlide((prev) => (prev === 0 ? slides.length - 1 : prev - 1)); + }; + + if (!slides || slides.length === 0) { + return
Нет слайдов для отображения
; + } + + return ( +
+
+ + + + aaaaaa + + +
+

{slides[currentSlide].nameSlide}

+ {slides[currentSlide].text} +
+ +
+ {slides[currentSlide].calibr} + {slides[currentSlide].diametr} +
+
+
+ ); +} @@ -0,0 +1,103 @@ +.container { + display: flex; + transition: transform 0.5s ease-in-out; + width: 2rem; +} + +.prevbtn, +.nextbtn { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: rgba(255, 255, 255, 0.5); + border-radius: 100px; + color: white; + border: none; + padding: 8px 16px 8px 16px; + cursor: pointer; + font-size: 18px; + font-weight: bold; + z-index: 2; +} + +.prevbtn { + margin-left: 58.7rem; +} + +.nextbtn { + margin-left: 90rem; +} + +.slide { + transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out; +} + +.slideContent { + text-align: justify; + color: #ffffff; + margin-left: 8rem; +} +h1 { + margin-top: 15rem; + font-family: "Orbitron", sans-serif; + font-size: 9.875rem; + padding-bottom: 3rem; +} +.slideText { + font-family: "Didact Gothic", sans-serif; + font-size: 1.125rem; + color: #ffffff; + position: absolute; + margin-left: 102rem; + gap: 1rem; + flex-direction: column; + display: flex; + margin-top: 15rem; + width: 13rem; + word-spacing: 5rem; +} + +.description { + font-family: "Didact Gothic", sans-serif; + font-size: 1.125rem; + width: 100%; +} +.slideImage { + position: absolute; + padding-left: 63rem; + display: flex; + padding-top: 12rem; + animation: 0.5s ease-in-out forwards; + width: 74%; +} + +.slide.next { + animation: slideInNext 0.5s ease-in-out forwards; +} + +.slide.prev { + animation: slideInPrev 0.5s ease-in-out forwards; +} + +@keyframes slideInNext { + 0% { + transform: translateX(100%); + opacity: 0; + } + 100% { + transform: translateX(0); + opacity: 1; + } +} + +@keyframes slideInPrev { + 0% { + transform: translateX(-100%); + opacity: 0; + } + 100% { + transform: translateX(0); + opacity: 1; + } +} + @@ -0,0 +1,32 @@ +import styles from './Cards.module.css' +import { useState } from 'react'; +import { useCart } from '../../hooks/UseCart.js'; + +export const Card = ({ id, title, description, photo, price }) => { + const { addToCart } = useCart(); + const [isAdding, setIsAdding] = useState(false); + const handleAddToCart = () => { + setIsAdding(true); + addToCart({ id, title, description, photo, price }); + setTimeout(() => { + setIsAdding(false); + }, 300); + }; + return ( +
+

{title}

+ aaaa + {description} +
+ {price}$ + +
+
+ ); +}; \ No newline at end of file @@ -0,0 +1,40 @@ +import styles from './Cards.module.css' +import { cardsData } from '../constants.js' +import { Card } from './Card.jsx'; + +export default function CardsGrid(){ + const chunkArray = (array, chunkSize) => { + const result = []; + for (let i = 0; i < array.length; i += chunkSize) { + result.push(array.slice(i, i + chunkSize)); + } + return result; + }; + + const cardGroups = chunkArray(cardsData, 3); + const backgroundStyle = { + backgroundImage: `url(${process.env.PUBLIC_URL}/images/fon.svg)`, + backgroundSize: 'cover', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat' + }; + return ( +
+ {cardGroups.map((group, groupIndex) => ( +
+ {group.map((card) => ( + + ))} +
+ ))} +
+ ); +}; + + @@ -0,0 +1,82 @@ + +.container { + margin-left: 3rem; + margin-right: 3rem; + padding: 10px; + padding-top: 10rem; + +} +.image{ + width: 17rem; + height: auto; + padding-top: 2.3rem; + margin-bottom: 2.625rem; + max-height: 34rem; + +} +.row { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 4rem; + margin-bottom: 10rem; + text-align: center; +} +.card { + text-align: center; + border-radius: 8px; + padding: 20px; + transition: transform 0.3s ease; +} + +.card:hover { + transform: translateY(-5px); + +} + +.title { + font-family: "Orbitron", sans-serif; + font-size: 3rem; + margin-bottom: 10px; + color: #000000; + text-align: center; + +} + +.description { + margin-left: 6.5rem; + font-family: "Didact Gothic", sans-serif; + font-size: 1.125rem; + line-height: 1.5; + color: #000000; + margin-bottom: 15px; + display: flex; + text-align: justify; + width: 20rem; +} + +.footer { + display: flex; + justify-content: space-between; + align-items: center; +} + +.counter { + font-family: "Orbitron", sans-serif; + font-size: 1.5rem; + margin-left: 3.5625rem; + padding-top: 0.623rem; + font-weight: bold; + color: #000000; +} +.addToCartButton{ + display: flex; + width: 11.625rem; + background-color: #000000; + height: 2.875rem; + display: flex; + font-family: "Didact Gothic", sans-serif; + font-size: 1.25rem; + color: #ffffff; + padding-left: 3rem; + padding-top: 0.623rem; +} @@ -0,0 +1,46 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + + +export default function Loader() { + + +const navigate = useNavigate(); + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + + + useEffect(() => { + const loadUserData = () => { + setIsLoading(true); + try { + const savedUser = localStorage.getItem('currentUser'); + if (savedUser) { + const userData = JSON.parse(savedUser); + setUser(userData); + + } else { + navigate('/login'); + } + } catch (error) { + console.error('Ошибка загрузки данных пользователя:', error); + } finally { + setIsLoading(false); + } + }; + loadUserData(); + }, [navigate]); + if (isLoading) { + return ( +
+ +
Загрузка профиля...
+
+ ); + } + + if (!user) { + return null; + } +} \ No newline at end of file @@ -0,0 +1,136 @@ + +export const guestNavItems = [ + { id: 'home', title: 'Главная страница', path: '/', label: 'Главная' }, + { id: 'catalog', title: 'Каталог товаров', path: '/catalog', label: 'Каталог' }, + { id: 'about', title: 'О нашей компании', path: '/about', label: 'О нас' }, + { id: 'login', title: 'Вход в систему', path: '/login', label: 'Войти' }, + ]; + +export const authNavItems = [ + + { id: 'home', title: 'Главная страница', path: '/', label: 'Главная' }, + { id: 'catalog', title: 'Каталог товаров', path: '/catalog', label: 'Каталог' }, + { id: 'about', title: 'О нашей компании', path: '/about', label: 'О нас' }, + { id: 'profile', title: 'Личный кабинет', path: '/profile', label: 'Профиль' }, + { id: 'basket', title: 'Корзина покупок', path: '/basket', label: 'Корзина' }, + ]; + +export const footer = [ + { + id: "section-1", + className: "link", + links: [ + { id: 1, path: "/404", title: "О нас" }, + { id: 2, path: "/404", title: "Политика обработки персональных данных" }, + { id: 3, path: "/404", title: "Документы на веб-сайте" }, + { id: 4, path: "", title: "` " }, + { id: 5, path: "", title: "` " }, + { id: 6, path: "/404", title: "Вопросы и ответы" }, + { id: 7, path: "/404", title: "Заказы и доставка" }, + { id: 8, path: "/404", title: "Возврат товара" } + ] + }, + { + id: "section-2", + className: "linkSocial", + links: [ + { id: 9, path: "404", title: "INSTAGRAM", external: true }, + { id: 10, path: "404", title: "VK", external: true }, + { id: 11, path: "404", title: "YOUTUBE", external: true }, + { id: 12, path: "404", title: "TELEGRAM", external: true } + ] + } +]; + +export const slides = [ + { + id: 1, + img: "/images/rolex.svg", + nameSlide: "ROLEX", + text: "Коллекция Rolex представлена престижными и высокоточными часовыми моделями на любой вкус, от Профессиональных до Классических.", + calibr: "калибр 7135", + diametr: "диаметр 40мм", + }, + { + id: 2, + img: "/images/longines.svg", + nameSlide: "Longines", + text: "Коллекция Longines представлена престижными и высокоточными часовыми моделями на любой вкус, от Профессиональных до Классических.", + calibr: "калибр 8175", + diametr: "диаметр 36мм", + }, + { + id: 3, + img: "/images/marvin.svg", + nameSlide: "MARVIN", + text: "Коллекция MARVIN представлена престижными и высокоточными часовыми моделями на любой вкус, от Профессиональных до Классических.", + calibr: "калибр 3671", + diametr: "диаметр 36мм", + }, + ]; + +export const cardsData = [ + { + id: 1, + title: "ROLEX", + photo:'/images/rolex.svg', + description: "Ролекс - роскошные часы с классическим дизайном, прочными корпусами и высокоточными механизмами.", + price: 10000, + }, + { + id: 2, + title: "LONGINES", + photo:'/images/longines.svg', + description: "Longines - швейцарские часы с длинной истории и традициями. Известны своей элегантностью, точностью и качеством.", + price: 12000, + }, + { + id: 3, + title: "MARVIN", + photo:'/images/marvin.svg', + description: "MARVIN известен своими точными механическими часами, которые пользуются популярностью.", + price: 19000, + }, + { + id: 4, + title: "ZENITH", + photo:'/images/zenith.svg', + description: "Зенит известна своей инновационной технологией и высокой точностью. Одним из самых известных моделей Зенита является Эль-Примо.", + price: 11000, + }, + { + id: 5, + title: "PAUL HEITT", + photo:'/images/paul.svg', + description: "Пол Хевитт известен своими стильными и функциональными часами, которые сочетают в себе современный дизайн и высокую точность.", + price: 22000, + }, + { + id: 6, + title: "LONGINES", + photo:'/images/longines2.svg', + description: "Longines - швейцарские часы с длинной истории и традициями. Известны своей элегантностью, точностью и качеством.", + price: 10000, + }, + { + id: 7, + title: "Hampden", + photo:'/images/hampden.svg', + description: "Хэмпден известен своими высокоточными часами и механизмами, которые производятся вручную в Шотландии", + price: 11000, + }, + { + id: 8, + title: "ROLEX", + photo:'/images/rolex2.svg', + description: "Ролекс - роскошные часы с классическим дизайном, прочными корпусами и высокоточными механизмами.", + price: 22000, + }, + { + id: 9, + title: "OMEGA", + photo:'/images/omega.svg', + description: "Omega - это швейцарская марка часов, известная своей высокой точностью, инновациями и историческими достижениями.", + price: 12000, + }, +]; @@ -0,0 +1,73 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +export function useAuth(redirectToLogin = true) { + const navigate = useNavigate(); + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isAuthenticated, setIsAuthenticated] = useState(false); + + useEffect(() => { + const loadUserData = () => { + setIsLoading(true); + try { + const savedUser = localStorage.getItem('currentUser'); + if (savedUser) { + const userData = JSON.parse(savedUser); + setUser(userData); + setIsAuthenticated(true); + } else { + setUser(null); + setIsAuthenticated(false); + if (redirectToLogin) { + navigate('/login'); + } + } + } catch (error) { + console.error('Ошибка загрузки данных пользователя:', error); + setUser(null); + setIsAuthenticated(false); + } finally { + setIsLoading(false); + } + }; + + loadUserData(); + + const handleStorageChange = (e) => { + if (e.key === 'currentUser') { + loadUserData(); + } + }; + + window.addEventListener('storage', handleStorageChange); + + return () => { + window.removeEventListener('storage', handleStorageChange); + }; + }, [navigate, redirectToLogin]); + + const logout = () => { + localStorage.removeItem('currentUser'); + setUser(null); + setIsAuthenticated(false); + if (redirectToLogin) { + navigate('/login'); + } + }; + + const login = (userData) => { + localStorage.setItem('currentUser', JSON.stringify(userData)); + setUser(userData); + setIsAuthenticated(true); + }; + + return { + user, + isLoading, + isAuthenticated, + login, + logout, + setUser + }; +} \ No newline at end of file @@ -0,0 +1,70 @@ +import { useState, useEffect } from 'react'; + +export const useCart = () => { + const [cart, setCart] = useState(() => { + try { + const savedCart = localStorage.getItem('cart'); + return savedCart ? JSON.parse(savedCart) : []; + } catch (error) { + return []; + } + }); + + useEffect(() => { + localStorage.setItem('cart', JSON.stringify(cart)); + }, [cart]); + + const addToCart = (product) => { + if (!product || !product.id) { + return; + } + + setCart(prevCart => { + const existingItem = prevCart.find(item => item.id === product.id); + + if (existingItem) { + return prevCart.map(item => + item.id === product.id + ? { ...item, quantity: item.quantity + 1 } + : item + ); + } else { + return [...prevCart, { + id: product.id, + title: product.title || product.name || 'Без названия', + description: product.description || '', + price: Number(product.price) || 0, + photo: product.photo || product.image || '', + quantity: 1 + }]; + } + }); + }; + + const removeFromCart = (productId) => { + setCart(prevCart => prevCart.filter(item => item.id !== productId)); + }; + + + + const clearCart = () => { + setCart([]); + }; + + const calculateTotal = () => { + return cart.reduce((total, item) => total + (item.price * item.quantity), 0); + }; + + const calculateItemsCount = () => { + return cart.reduce((total, item) => total + item.quantity, 0); + }; + + return { + cart, + addToCart, + removeFromCart, + clearCart, + calculateTotal, + calculateItemsCount + }; +}; \ No newline at end of file @@ -0,0 +1,56 @@ +import Footer from "../../components/Footer/Footer"; +import styles from './About.module.css' + +export default function Catalog(){ + return( + <> +
+
+