@@ -0,0 +1,3 @@ + + + @@ -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,223 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +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'; +import { useCart } from '../CartContext.jsx'; + +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, + updateQuantity, + removeFromCart, + clearCart, + calculateTotalCart, + calculateItemsCountCart + } = 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: calculateTotalCart(), + 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} оформлен на сумму $${calculateTotalCart()}`); + clearCart(); + navigate('/basket'); + }; + + if (isLoading) { + return ( +
+
+
+

Загрузка...

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

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

+

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

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

Корзина

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

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

+
+ +
+ +
+ {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} + /> +
+ +

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

+
+ +
+
+ К оплате: + ${calculateTotalCart().toLocaleString()} +
+ + +
+
+
+ ); +} \ No newline at end of file @@ -0,0 +1,702 @@ +.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; + max-width: 40vw; +} + +.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: #6f6f6f; + 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; + color: #fff; +} + +.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: rgb(0, 0, 0); + border-radius: 10px; + margin-bottom: 30px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +.checkboxWrapper{ + display: flex; + gap: 2rem; +} + +.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,67 @@ +import styles from "./BasketMain.module.css"; + +export default function CartItem({ item, onUpdateQuantity, onRemove }) { + const handleDecrease = () => { + if (item.quantity > 1) { + onUpdateQuantity(item.quantity - 1); + } else { + onRemove(item.id); + } + }; + + const handleIncrease = () => { + onUpdateQuantity(item.quantity + 1); + }; + + 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,35 @@ +import styles from './BasketMain.module.css'; + +export default function CheckboxInput({ + id, + name, + checked, + onChange, + label, + required = false, + className = '', + ...props +}) { + const checkboxId = id || `checkbox-${name}`; + + 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,204 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import styles from "./Profile.module.css"; +import toast from 'react-hot-toast'; + +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()) { + toast('Все поля обязательны для заполнения'); + 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); + toast('Данные успешно обновлены!'); + }; + + 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,51 @@ +import styles from './Footer.module.css'; +import { Link } from 'react-router-dom'; + +export default function Footer({footer = []}) { + const renderLink = (link) => { + if (link.external) { + return ( + + {link.title} + + ); + } + + return ( + + {link.title} + + ); + }; + + return ( + + ); +} \ No newline at end of file @@ -0,0 +1,53 @@ +.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; + position: absolute; + gap: 1rem; + width: auto; + font-family: "Didact Gothic", sans-serif; + font-size: 1rem; + color: #ffffff; + margin-top: 4rem; + text-decoration: none; + padding-right: 7rem; + margin-left: 105rem; +} +a{ + color: #ffffff; + text-decoration: none; +} +.linkItem{ + text-decoration: none; + color: #ffffff; +} +.footer{ + background-color: black; +} + +.linksContainer{ + padding-bottom: 2rem; + display: grid; +} \ No newline at end of file @@ -0,0 +1,70 @@ +import { Link } from 'react-router-dom'; +import styles from './Header.module.css'; + + +export default function Header({guestNavItems = [], authNavItems = [], useAuth = [] }) { + 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,13 @@ +import styles from './MainButton.module.css' +import { Link } from 'react-router-dom'; + +export default function MainButton() { + return ( + + + + ); +} @@ -0,0 +1,280 @@ +.cssbuttonsIoButton { + font-family: "Orbitron", sans-serif; + background: #ebebeb; + color: rgb(0, 0, 0); + padding: 0.35em; + padding-left: clamp(2.5rem, 5vw, 3.5rem); + font-size: clamp(14px, 1.5vw, 17px); + font-weight: 600; + border-radius: 0.25rem; + border: none; + letter-spacing: 0.05em; + display: flex; + align-items: center; + overflow: hidden; + position: relative; + height: clamp(2.4em, 5vh, 2.8em); + padding-right: clamp(6rem, 10vw, 8rem); + cursor: pointer; + min-width: 150px; + width: fit-content; + max-width: 400px; + margin-top: 8vw; + margin-left: 2vw; +} + +.icon { + background: #6386ba; + position: absolute; + display: flex; + align-items: center; + justify-content: center; + height: clamp(2.2em, 4.5vh, 2.5em); + width: clamp(2.2em, 4.5vh, 2.5em); + border-radius: 0.25rem; + right: 0.3em; + transition: all 0.3s; + padding: clamp(10px, 2vw, 13px); +} + +.cssbuttonsIoButton:hover .icon { + width: calc(100% - 0.6em); +} + +.cssbuttonsIoButton .icon svg { + width: clamp(1em, 2vw, 1.1em); + transition: transform 0.3s; + color: #ffffff; +} + +.cssbuttonsIoButton:hover .icon svg { + transform: translateX(0.1em); +} + +.cssbuttonsIoButton:active .icon { + transform: scale(0.95); +} + +.mainButton { + cursor: pointer; + text-decoration: none; +} + +.mainButton:visited { + color: inherit; +} + +.mainButton { + position: absolute; + margin-top: min(15rem, 15vh); + margin-left: min(8.0625rem, 5vw); +} + +@media screen and (max-width: 1400px) { + .mainButton { + margin-left: clamp(3rem, 4vw, 6rem); + } +} + +@media screen and (max-width: 1200px) { + .mainButton { + margin-left: clamp(2.5rem, 3.5vw, 5rem); + margin-top: clamp(12rem, 12vh, 14rem); + } +} + +@media screen and (max-width: 1024px) { + .mainButton { + margin-left: clamp(2rem, 3vw, 4rem); + margin-top: clamp(10rem, 10vh, 12rem); + } + + .cssbuttonsIoButton { + padding-left: clamp(2rem, 4vw, 2.8rem); + padding-right: clamp(5rem, 8vw, 6.5rem); + min-width: 140px; + } +} + +@media screen and (max-width: 900px) { + .mainButton { + position: relative; + margin: clamp(8rem, 8vh, 10rem) auto 0; + left: 0; + transform: none; + display: flex; + justify-content: center; + width: 100%; + } + + .cssbuttonsIoButton { + margin: 0 auto; + } +} + +@media screen and (max-width: 768px) { + .mainButton { + margin-top: clamp(6rem, 6vh, 8rem); + } + + .cssbuttonsIoButton { + padding-left: clamp(1.8rem, 3.5vw, 2.3rem); + padding-right: clamp(4.5rem, 7vw, 5.8rem); + font-size: clamp(13px, 1.4vw, 16px); + height: clamp(2.2em, 4.2vh, 2.6em); + min-width: 135px; + } + + .icon { + height: clamp(2em, 3.9vh, 2.3em); + width: clamp(2em, 3.9vh, 2.3em); + padding: clamp(8px, 1.8vw, 12px); + } +} + +@media screen and (max-width: 640px) { + .mainButton { + margin-top: clamp(5rem, 5vh, 6rem); + } + + .cssbuttonsIoButton { + padding-left: clamp(1.6rem, 3vw, 2rem); + padding-right: clamp(4rem, 6vw, 5rem); + font-size: clamp(12.5px, 1.3vw, 15px); + min-width: 130px; + } + + .icon { + right: 0.25em; + } +} + +@media screen and (max-width: 480px) { + .mainButton { + margin-top: clamp(4rem, 4vh, 5rem); + } + + .cssbuttonsIoButton { + padding-left: clamp(1.4rem, 2.8vw, 1.8rem); + padding-right: clamp(3.5rem, 5.5vw, 4.5rem); + font-size: clamp(12px, 1.2vw, 14px); + height: clamp(2.1em, 3.8vh, 2.4em); + min-width: 125px; + } + + .icon { + height: clamp(1.9em, 3.6vh, 2.1em); + width: clamp(1.9em, 3.6vh, 2.1em); + padding: clamp(7px, 1.6vw, 10px); + right: 0.2em; + } + + .cssbuttonsIoButton .icon svg { + width: clamp(0.9em, 1.8vw, 1em); + } +} + +@media screen and (max-width: 375px) { + .cssbuttonsIoButton { + padding-left: clamp(1.3rem, 2.5vw, 1.6rem); + padding-right: clamp(3.2rem, 5vw, 4rem); + font-size: 12px; + min-width: 120px; + } + + .icon { + padding: 6px; + } +} + +@media screen and (min-width: 1920px) { + .mainButton { + margin-left: clamp(8rem, 6vw, 12rem); + margin-top: clamp(15rem, 16vh, 20rem); + } +} + +@media screen and (min-width: 2560px) { + .mainButton { + margin-left: clamp(10rem, 8vw, 15rem); + margin-top: clamp(18rem, 18vh, 25rem); + } +} + +@media screen and (orientation: portrait) and (max-width: 768px) { + .mainButton { + margin-top: clamp(5rem, 8vh, 7rem); + } + + .cssbuttonsIoButton { + font-size: clamp(13px, 1.6vw, 15px); + padding-left: clamp(1.8rem, 4vw, 2.5rem); + padding-right: clamp(4.5rem, 8vw, 6rem); + } +} + +@media screen and (orientation: landscape) and (max-height: 600px) { + .mainButton { + margin-top: clamp(3rem, 4vh, 5rem); + } + + .cssbuttonsIoButton { + height: clamp(2.2em, 6vh, 2.5em); + font-size: clamp(12px, 1.8vw, 14px); + } + + .icon { + height: clamp(2em, 5.5vh, 2.3em); + width: clamp(2em, 5.5vh, 2.3em); + } +} + + + +@media (hover: none) and (pointer: coarse) { + .cssbuttonsIoButton:hover .icon { + width: clamp(2.2em, 4.5vh, 2.5em); + } + + .cssbuttonsIoButton:active .icon { + width: calc(100% - 0.6em); + } + + .cssbuttonsIoButton:active .icon svg { + transform: translateX(0.1em); + } +} + +.cssbuttonsIoButton span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: inherit; +} + +.cssbuttonsIoButton, +.icon, +.mainButton { + transition: all 0.3s ease; +} + +@media screen and (max-width: 320px) { + .cssbuttonsIoButton { + padding-left: 1.2rem; + padding-right: 3.2rem; + font-size: 11px; + min-width: 115px; + height: 2.1em; + } + + .icon { + height: 1.8em; + width: 1.8em; + padding: 5px; + right: 0.15em; + } + + .cssbuttonsIoButton .icon svg { + width: 0.85em; + } +} \ No newline at end of file @@ -0,0 +1,51 @@ +import { useState } from "react"; +import styles from './Slider.module.css'; + +export default function Slide({ slides = [] }) { + 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 ( +
+
+ + + + + +
+

{slides[currentSlide].nameSlide}

+ {slides[currentSlide].text} +
+ +
+ {slides[currentSlide].calibr} + {slides[currentSlide].diametr} +
+
+
+ ); +} \ No newline at end of file @@ -0,0 +1,236 @@ +.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; + cursor: pointer; + font-size: 18px; + font-weight: bold; + z-index: 2; +} + +.prevbtn { + left: 48vw; +} + +.nextbtn { + right: 22vw; +} + +.slide { + transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out; +} + +.slideContent { + text-align: justify; + color: #ffffff; + padding-left: 5%; + padding-right: 5%; +} + +h1 { + margin-top: 20vh; + font-family: "Orbitron", sans-serif; + font-size: clamp(3rem, 12vw, 9.875rem); + padding-bottom: 3rem; + text-align: center; + margin-left: 4vw; +} + +.slideText { + font-family: "Didact Gothic", sans-serif; + font-size: clamp(1rem, 1.5vw, 1.125rem); + color: #ffffff; + position: relative; + margin: 0 auto; + gap: 1rem; + flex-direction: column; + display: flex; + margin-top: 29vh; + width: min(90%, 13rem); + word-spacing: normal; + margin-left: 80vw; + position: absolute; +} + +.description { + font-family: "Didact Gothic", sans-serif; + font-size: clamp(1rem, 1.5vw, 1.125rem); + width: 100%; + max-width: 800px; + margin: 0 auto; + position: absolute; + width: 30vw; + margin-left: 6rem; +} + +.slideImage { + position: absolute; + display: flex; + justify-content: center; + margin: 12vh auto 0; + animation: 0.5s ease-in-out forwards; + width: 28rem; + display: flex; + margin-left: 52vw; + margin-top: 18vh; +} + +.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; + } +} + +@media (max-width: 1024px) { + .prevbtn, + .nextbtn { + padding: 6px 12px; + font-size: 16px; + } + + .slideText { + margin-top: 10vh; + width: min(95%, 13rem); + } + + .slideImage { + margin-top: 8vh; + width: min(95%, 90rem); + } +} + +@media (max-width: 768px) { + h1 { + margin-top: 10vh; + font-size: clamp(2.5rem, 10vw, 5rem); + padding-bottom: 2rem; + } + + .prevbtn, + .nextbtn { + padding: 5px 10px; + font-size: 14px; + } + + .slideText { + margin-top: 5vh; + width: 90%; + } + + .slideImage { + margin-top: 5vh; + width: 95%; + } + + .slideContent { + padding-left: 3%; + padding-right: 3%; + } +} + +@media (max-width: 480px) { + h1 { + margin-top: 8vh; + font-size: clamp(2rem, 8vw, 3.5rem); + padding-bottom: 1.5rem; + } + + .prevbtn, + .nextbtn { + padding: 4px 8px; + font-size: 12px; + } + + .slideText { + margin-top: 4vh; + width: 95%; + font-size: 0.9rem; + } + + .slideImage { + margin-top: 4vh; + width: 98%; + } + + .description { + font-size: 0.9rem; + } +} + +@media (min-width: 1600px) { + .slideContent { + padding-left: 10%; + padding-right: 10%; + } + + .slideImage { + max-width: 1400px; + } +} + +@media (max-height: 600px) { + h1 { + margin-top: 8vh; + font-size: clamp(2rem, 8vh, 5rem); + } + + .slideText { + margin-top: 8vh; + } + + .slideImage { + margin-top: 8vh; + } +} + +@media (orientation: landscape) and (max-height: 500px) { + h1 { + margin-top: 5vh; + font-size: clamp(2rem, 6vh, 4rem); + } + + .slideText { + margin-top: 5vh; + } + + .slideImage { + margin-top: 5vh; + width: 60%; + } +} \ No newline at end of file @@ -0,0 +1,37 @@ +import { useState } from 'react'; +import { useCart } from '../CartContext.jsx'; +import styles from './Cards.module.css'; + +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}

+ {title} + {description} + +
+ {price}$ + +
+
+ ); +}; \ No newline at end of file @@ -0,0 +1,39 @@ +import styles from './Cards.module.css' +import { Card } from './Card.jsx'; + +export default function CardsGrid({cardsData = []}){ + 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: auto; + height: 45vh; + 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; + height: 10vh; +} + +.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,97 @@ +import { createContext, useContext, useState, useEffect } from 'react'; + +const CartContext = createContext(); + +export const useCart = () => { + const context = useContext(CartContext); + return context; +}; + +export const CartProvider = ({ children }) => { + 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 updateQuantity = (productId, quantity) => { + if (quantity < 1) { + removeFromCart(productId); + return; + } + + setCart(prevCart => + prevCart.map(item => + item.id === productId + ? { ...item, quantity } + : item + ) + ); + }; + + const removeFromCart = (productId) => { + setCart(prevCart => prevCart.filter(item => item.id !== productId)); + }; + + const clearCart = () => { + setCart([]); + }; + + const calculateTotalCart = () => { + return cart.reduce((total, item) => total + (item.price * item.quantity), 0); + }; + + const calculateItemsCountCart = () => { + return cart.reduce((total, item) => total + item.quantity, 0); + }; + + const value = { + cart, + addToCart, + updateQuantity, + removeFromCart, + clearCart, + calculateTotalCart, + calculateItemsCountCart + }; + + return ( + + {children} + + ); +}; \ No newline at end of file @@ -0,0 +1,40 @@ +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,139 @@ +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 footerSections = [ + { + id: "section-1", + className: "link", + links: [ + { id: 1, path: "/about", title: "О нас" }, + { id: 2, path: "/privacy", title: "Политика обработки персональных данных" }, + { id: 3, path: "/agreement", title: "Пользовательское соглашение" }, + ] + }, + { + id: "section-2", + className: "link", + links: [ + { id: 4, path: "/catalog", title: "Перейти в каталог" }, + { id: 5, path: "/basket", title: "Корзина" }, + { id: 6, path: "/profile", title: "Ваш профиль" } + ] + }, + { + id: "section-3", + className: "linkSocial", + links: [ + { id: 7, path: "https://www.instagram.com/", title: "INSTAGRAM", external: true }, + { id: 8, path: "https://vk.com/", title: "VK", external: true }, + { id: 9, path: "https://www.youtube.com", title: "YOUTUBE", external: true }, + { id: 10, path: "https://web.telegram.org/", 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,18 @@ +import { useLocation } from 'react-router-dom'; + +export function useFooter() { + const location = useLocation(); + + const noPaths = [ + '/login', + '/registration', + '/profile', + '/', + ]; + + const hideFooter = noPaths.some(path => + location.pathname === path || location.pathname.startsWith(`${path}/`) + ); + + return !hideFooter; +} \ No newline at end of file @@ -0,0 +1,55 @@ +import styles from './About.module.css'; + +export default function Catalog() { + return ( + <> +
+
+ + ); +} \ No newline at end of file @@ -0,0 +1,73 @@ +.container { + background-color: black; + display: grid; + justify-content: center; +} + +.video { + width: 98rem; + margin-top: 10rem; +} + +.img { + width: 98rem; +} + +.block { + margin-top: 9.75rem; + display: flex; + color: #000; +} + +.aboutText { + font-family: "Didact Gothic", sans-serif; + font-size: 1.5rem; + width: 40rem; + position: absolute; + margin-top: 9.7rem; + margin-left: 8.18rem; + text-align: justify; +} + +.aboutText2 { + font-family: "Didact Gothic", sans-serif; + font-size: 1.5rem; + width: 24rem; + position: absolute; + margin-top: 47.5rem; + margin-left: 73.125rem; + text-align: justify; +} + + +.logo { + font-family: "Orbitron", sans-serif; + font-optical-sizing: auto; + font-weight: weight; + font-style: normal; + font-size: 4rem; + color: #ffffff; + position: absolute; + margin-left: 8.125rem; + margin-top: 1.5rem; +} + +.men { + width: 29.7rem; +} + +.fon { + width: 63.7rem; + margin-left: 4.5rem; +} + +.text { + color: #000000; + position: absolute; + width: 57rem; + text-align: justify; + font-family: "Didact Gothic", sans-serif; + font-size: 1.15rem; + margin-left: 39.4rem; + margin-top: 2rem; +} \ No newline at end of file @@ -0,0 +1,188 @@ +import { useState } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { useForm } from 'react-hook-form'; +import styles from "./Login.module.css"; + +export default function Login() { + const navigate = useNavigate(); + const { + register, + handleSubmit, + formState: { errors }, + clearErrors, + setValue, + trigger + } = useForm({ + mode: 'onSubmit', + defaultValues: { + email: '', + password: '' + } + }); + + const [isLoading, setIsLoading] = useState(false); + const [serverError, setServerError] = useState(''); + + const onSubmit = async (data) => { + const isValid = await trigger(); + + if (!isValid) { + Object.keys(errors).forEach(fieldName => { + setValue(fieldName, ''); + }); + return; + } + + setServerError(''); + setIsLoading(true); + + try { + await new Promise(resolve => setTimeout(resolve, 1000)); + + const users = JSON.parse(localStorage.getItem('registeredUsers') || '[]'); + const user = users.find(u => u.email === data.email); + + if (!user) { + setServerError('Пользователь с таким email не найден'); + setIsLoading(false); + return; + } + + if (user.password !== data.password) { + setServerError('Неверный пароль'); + setIsLoading(false); + return; + } + + const userSessionData = { + email: user.email, + fullName: user.fullName || 'Пользователь', + phone: user.phone || '', + registeredAt: user.registeredAt || new Date().toISOString() + }; + + localStorage.setItem('currentUser', JSON.stringify(userSessionData)); + navigate('/profile'); + + } catch (error) { + setServerError('Ошибка сервера. Попробуйте позже.'); + } finally { + setIsLoading(false); + } + }; + + const getInputClass = (fieldName) => { + if (errors[fieldName]) { + return `${styles.input} ${styles.inputError}`; + } + return styles.input; + }; + + const getPlaceholder = (fieldName, defaultPlaceholder) => { + if (errors[fieldName]) { + return ''; + } + return defaultPlaceholder; + }; + + const handleInputChange = (e) => { + const { name } = e.target; + + if (errors[name]) { + clearErrors(name); + } + + if (serverError) { + setServerError(''); + } + }; + + const handleBlur = async (fieldName) => { + const isValid = await trigger(fieldName); + + if (!isValid && errors[fieldName]) { + setValue(fieldName, ''); + } + }; + + return ( +
+ Вход + +
+
+
+ handleBlur('email') + })} + /> + {errors.email && ( +
+ {errors.email.message} +
+ )} +
+ +
+ handleBlur('password') + })} + /> + {errors.password && ( +
+ {errors.password.message} +
+ )} +
+ + {serverError && ( +
+ {serverError} +
+ )} + + + Нет аккаунта? Регистрация + +
+ +
+ + Фон входа +
+ ); +} \ No newline at end of file @@ -0,0 +1,262 @@ +.container { + background-color: black; + padding-bottom: 14.3rem; + position: relative; + width: 100%; + overflow-x: hidden; +} + +.fon { + width: 100%; + max-width: 78.375rem; + height: auto; + padding-top: 13.125rem; + margin: 0 auto; + display: flex; + width: 100vw; +} + +.h1 { + font-family: "Orbitron", sans-serif; + font-size: clamp(2rem, 8vw, 4rem); + color: #ffffff; + font-weight: 700; + position: absolute; + top: 15.1875rem; + left: 50%; + transform: translateX(-50%); + text-align: center; + width: 90%; + margin: 0; +} + +.group { + position: absolute; + display: grid; + top: 30rem; + left: 50%; + transform: translateX(-50%); + gap: 1rem; + width: 90%; + max-width: 41.75rem; + margin: 0; +} + +.input { + width: 100%; + height: 3.75rem; + padding-left: 1rem; + border-radius: 12px; + border: 1.5px solid rgb(255, 255, 255); + outline: none; + transition: all 0.3s cubic-bezier(0.19, 1, 0.22, 1); + box-shadow: 0px 0px 20px -18px; + background-color: #f4f4f4ae; + font-family: "Didact Gothic", sans-serif; + font-size: clamp(0.9rem, 2vw, 1.1rem); + color: #000000; +} + +.input:hover { + border: 2px solid rgb(255, 255, 255); + box-shadow: 0px 0px 20px -17px; +} + +.input:active { + transform: scale(0.95); +} + +.input:focus { + border: 2px solid rgb(255, 255, 255); +} + +.button { + position: absolute; + width: 90%; + max-width: 24.0625rem; + height: 3.75rem; + background-color: #ffffff; + border-radius: 0.625rem; + top: 43.25rem; + left: 50%; + transform: translateX(-50%); + margin: 0; +} + +.buttontext { + font-family: "Orbitron", sans-serif; + font-size: clamp(1rem, 2.5vw, 1.25rem); + text-align: center; + display: block; + line-height: 3.75rem; +} + +.button:hover { + transform: translateX(-50%) scale(1.05); + cursor: pointer; +} + +.serverError{ + font-family: "Didact Gothic", sans-serif; + color: #c82828; + font-size: 1rem; + font-weight: 600; +} + +.text { + font-family: "Orbitron", sans-serif; + font-size: clamp(0.8rem, 2vw, 1rem); + color: #ffffff; + text-align: center; +} + +.link { + font-family: "Orbitron", sans-serif; + font-size: clamp(0.8rem, 2vw, 1rem); + color: #6262ff; +} + +.inputError { + border-color: #ff3838 !important; + border-width: 2px !important; + animation: shake 0.5s; +} + + +@media (max-width: 1200px) { + .fon { + padding-top: 10rem; + } + + .h1 { + top: 12rem; + } + + .group { + top: 25rem; + } + + .button { + top: 38rem; + } +} + +@media (max-width: 768px) { + .conteiner { + padding-bottom: 6rem; + } + + .fon { + padding-top: 8rem; + } + + .h1 { + top: 10rem; + font-size: clamp(1.5rem, 6vw, 3rem); + } + + .group { + top: 22rem; + gap: 0.8rem; + } + + .input { + height: 3.25rem; + } + + .button { + top: 34rem; + height: 3.25rem; + } + + .buttontext { + line-height: 3.25rem; + } +} + +@media (max-width: 480px) { + .conteiner { + padding-bottom: 4rem; + } + + .fon { + padding-top: 6rem; + } + + .h1 { + top: 8rem; + font-size: clamp(1.2rem, 5vw, 2rem); + } + + .group { + top: 18rem; + gap: 0.6rem; + } + + .input { + height: 3rem; + font-size: 0.9rem; + } + + .button { + top: 28rem; + height: 3rem; + } + + .buttontext { + line-height: 3rem; + font-size: 1rem; + } + + .text, .link { + font-size: 0.9rem; + } +} + +@media (max-width: 320px) { + .h1 { + top: 6rem; + } + + .group { + top: 15rem; + } + + .button { + top: 24rem; + } +} + +@media (orientation: portrait) { + .h1 { + width: 95%; + } + + .group { + width: 95%; + } + + .button { + width: 85%; + } +} + + +@media (orientation: landscape) and (max-height: 600px) { + .fon { + padding-top: 6rem; + } + + .h1 { + top: 8rem; + font-size: 2.5rem; + } + + .group { + top: 18rem; + } + + .button { + top: 28rem; + } +} @@ -0,0 +1,251 @@ +import { useState } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { useForm } from 'react-hook-form'; +import styles from './Registration.module.css'; + +export default function Registration() { + const navigate = useNavigate(); + const { + register, + handleSubmit, + formState: { errors }, + clearErrors, + setError, + setValue, + trigger + } = useForm({ + mode: 'onSubmit', + defaultValues: { + email: '', + fullName: '', + phone: '', + password: '', + } + }); + + const [isLoading, setIsLoading] = useState(false); + const [serverError, setServerError] = useState(''); + + const onSubmit = async (data) => { + const isValid = await trigger(); + + if (!isValid) { + Object.keys(errors).forEach(fieldName => { + setValue(fieldName, ''); + }); + return; + } + + setServerError(''); + setIsLoading(true); + + try { + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const existingUsers = JSON.parse(localStorage.getItem('registeredUsers') || '[]'); + const userExists = existingUsers.some(user => user.email === data.email); + + if (userExists) { + setError('email', { + type: 'manual', + message: 'Пользователь с таким email уже зарегистрирован' + }); + setValue('email', ''); + setIsLoading(false); + return; + } + + const userData = { + email: data.email, + fullName: data.fullName, + phone: data.phone, + password: data.password, + registeredAt: new Date().toISOString() + }; + + localStorage.setItem('currentUser', JSON.stringify(userData)); + localStorage.setItem( + 'registeredUsers', + JSON.stringify([...existingUsers, userData]) + ); + + setTimeout(() => { + navigate('/login'); + }, 2000); + } catch (error) { + console.error('Ошибка регистрации:', error); + setServerError('Ошибка при регистрации. Попробуйте позже.'); + } finally { + setIsLoading(false); + } + }; + + const getInputClass = (fieldName) => { + if (errors[fieldName]) { + return `${styles.input} ${styles.inputError}`; + } + return styles.input; + }; + + const getPlaceholder = (fieldName, defaultPlaceholder) => { + if (errors[fieldName]) { + return ''; + } + return defaultPlaceholder; + }; + + const handleInputChange = (e) => { + const { name } = e.target; + + if (errors[name]) { + clearErrors(name); + } + + if (serverError) { + setServerError(''); + } + }; + + const handleBlur = async (fieldName) => { + const isValid = await trigger(fieldName); + + if (!isValid && errors[fieldName]) { + setValue(fieldName, ''); + } + }; + + return ( +
+ Регистрация + +
+
+
+ handleBlur('email') + })} + /> + {errors.email && ( +
+ {errors.email.message} +
+ )} +
+ +
+ handleBlur('fullName') + })} + /> + {errors.fullName && ( +
+ {errors.fullName.message} +
+ )} +
+ +
+ handleBlur('phone') + })} + /> + {errors.phone && ( +
+ {errors.phone.message} +
+ )} +
+ +
+ handleBlur('password') + })} + /> + {errors.password && ( +
+ {errors.password.message} +
+ )} +
+ + {serverError && ( +
+ {serverError} +
+ )} + + + Уже есть аккаунт? + +  Войти + + +
+ + +
+ + Фон регистрации +
+ ); +} \ No newline at end of file @@ -0,0 +1,263 @@ +.container { + background-color: black; + padding-bottom: 9.5rem; + position: relative; + width: 100%; + overflow-x: hidden; + min-height: 100vh; +} + +.fon { + width: 100%; + max-width: 78.375rem; + height: auto; + padding-top: 13.125rem; + margin: 0 auto; + display: block; +} + +.h1 { + font-family: "Orbitron", sans-serif; + font-size: clamp(2rem, 8vw, 4rem); + color: #ffffff; + font-weight: 700; + position: absolute; + top: 15.1875rem; + left: 50%; + transform: translateX(-50%); + text-align: center; + width: 90%; + margin: 0; + white-space: nowrap; +} + +.group { + position: absolute; + display: grid; + top: 39vh; + left: 50%; + transform: translateX(-50%); + gap: 1rem; + width: 90%; + max-width: 41.75rem; + margin: 0; +} + +.input { + width: 100%; + height: 3.75rem; + padding-left: 1rem; + border-radius: 12px; + border: 1.5px solid rgb(255, 255, 255); + outline: none; + transition: all 0.3s cubic-bezier(0.19, 1, 0.22, 1); + box-shadow: 0px 0px 20px -18px; + background-color: #f4f4f4ae; + font-family: "Didact Gothic", sans-serif; + font-size: clamp(0.9rem, 2vw, 1.1rem); + color: #000000; +} + +.input:hover { + border: 2px solid rgb(255, 255, 255); + box-shadow: 0px 0px 20px -17px; +} + +.input:active { + transform: scale(0.95); +} + +.input:focus { + border: 2px solid rgb(255, 255, 255); +} + +.button { + position: absolute; + width: 90%; + max-width: 24.0625rem; + height: 3.75rem; + background-color: #ffffff; + border-radius: 0.625rem; + top: 72vh; + left: 50%; + transform: translateX(-50%); + margin: 0; + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.3s ease; +} + +.buttontext { + font-family: "Orbitron", sans-serif; + font-size: clamp(1rem, 2.5vw, 1.25rem); + text-align: center; + display: block; + color: #000000; +} + +.button:hover { + transform: translateX(-50%) scale(1.05); + cursor: pointer; +} + +.text { + font-family: "Orbitron", sans-serif; + font-size: clamp(0.8rem, 2vw, 1rem); + color: #ffffff; + text-align: center; +} + +.link { + font-family: "Orbitron", sans-serif; + font-size: clamp(0.8rem, 2vw, 1rem); + color: #6262ff; +} + +.serverError{ + font-family: "Didact Gothic", sans-serif; + color: #c82828; + font-size: 1rem; + font-weight: 600; +} + +.inputError { + border-color: #ff3838 !important; + border-width: 2px !important; + animation: shake 0.5s; +} + + +@media (max-width: 1200px) { + .fon { + padding-top: 11rem; + max-width: 90%; + } + + .h1 { + top: 13rem; + } +} + +@media (max-width: 768px) { + .conteiner { + padding-bottom: 7rem; + } + + .fon { + padding-top: 9rem; + } + + .h1 { + top: 11rem; + white-space: normal; + word-wrap: break-word; + } + + .group { + top: 35vh; + gap: 0.8rem; + } + + .input { + height: 3.25rem; + padding-left: 0.8rem; + } + + .button { + top: 68vh; + height: 3.25rem; + } + + .button:hover { + transform: translateX(-50%) scale(1.03); + } +} + +@media (max-width: 480px) { + .conteiner { + padding-bottom: 5rem; + } + + .fon { + padding-top: 7rem; + } + + .h1 { + top: 9rem; + font-size: clamp(1.5rem, 6vw, 2.5rem); + } + + .group { + top: 32vh; + gap: 0.6rem; + } + + .input { + height: 3rem; + padding-left: 0.7rem; + border-radius: 8px; + } + + .button { + top: 65vh; + height: 3rem; + border-radius: 8px; + } + + .text, .link { + font-size: clamp(0.7rem, 1.8vw, 0.9rem); + } +} + +@media (max-height: 600px) and (orientation: landscape) { + .fon { + padding-top: 6rem; + } + + .h1 { + top: 7rem; + } + + .group { + top: 30vh; + gap: 0.5rem; + } + + .button { + top: 60vh; + } + + .input { + height: 2.8rem; + } + + .button { + height: 2.8rem; + } +} + +@media (max-width: 320px) { + .h1 { + font-size: 1.5rem; + top: 8rem; + } + + .group { + top: 30vh; + } + + .input { + height: 2.8rem; + font-size: 0.8rem; + } + + .button { + height: 2.8rem; + top: 63vh; + } + + .buttontext { + font-size: 0.9rem; + } +} \ No newline at end of file @@ -0,0 +1,11 @@ +import Loader from "../../components/Loader"; +import Cart from "../../components/BasketMain/BasketMain"; + +export default function Basket(){ + return( +
+ + +
+ ) +} \ No newline at end of file @@ -0,0 +1,10 @@ +import CardsGrid from "../../components/Сards/Cards"; +import { cardsData } from "../../components/projectConstants"; + +export default function Catalog(){ + return( +
+ +
+ ) +} \ No newline at end of file @@ -0,0 +1,12 @@ +import styles from "./Error.module.css" + +export default function Error() { + return ( +
+
+

404

+ Страница не найдена +
+
+ ); +} \ No newline at end of file @@ -0,0 +1,19 @@ +.container{ + background-color: black; + width: 100vw; + height: 100vh; + font-family: "Orbitron", sans-serif; +} + +.main{ + color: #fff; + padding-top: 10rem; + display:grid; + justify-content: center; + align-items: center; + text-align: center; +} + +.text{ + font-size: 1.2rem; +} \ No newline at end of file @@ -0,0 +1,13 @@ +import styles from './Home.module.css' +import MainButton from "../../components/MainButton/MainButton" +import Slide from "../../components/Slider/Slide" +import { slides } from "../../components/projectConstants.js" + +export default function Home() { + return ( +
+ + +
+ ); +} \ No newline at end of file @@ -0,0 +1,10 @@ +.container { + font-size: 16px; + width: 100%; + height: 100vh; + background-size: cover; + background-image: url(/public/images/homeFon.svg); + background-repeat: no-repeat; + background-position: center; + min-height: 40rem; +} \ No newline at end of file @@ -0,0 +1,108 @@ +import styles from './PrivacyPolicy.module.css' + +export default function PrivacyPolicy(){ + return( + <> +
+
+ Политика в отношении обработки персональных данных +
+ 1. Общие положения
+ Настоящая политика обработки персональных данных составлена в соответствии с требованиями Федерального закона от 27.07.2006. № 152-ФЗ «О персональных данных» (далее — Закон о персональных данных) и определяет порядок обработки персональных данных и меры по обеспечению безопасности персональных данных, предпринимаемые Михайловым Иваном Сергеевичем (далее — Оператор).
+ 1.1. Оператор ставит своей важнейшей целью и условием осуществления своей деятельности соблюдение прав и свобод человека и гражданина при обработке его персональных данных, в том числе защиты прав на неприкосновенность частной жизни, личную и семейную тайну.
+ 1.2. Настоящая политика Оператора в отношении обработки персональных данных (далее — Политика) применяется ко всей информации, которую Оператор может получить о посетителях веб-сайта httpsː//thismywebsite·com.
+ 2. Основные понятия, используемые в Политике
+ 2.1. Автоматизированная обработка персональных данных — обработка персональных данных с помощью средств вычислительной техники. + 2.2. Блокирование персональных данных — временное прекращение обработки персональных данных (за исключением случаев, если обработка необходима для уточнения персональных данных).
+ 2.3. Веб-сайт — совокупность графических и информационных материалов, а также программ для ЭВМ и баз данных, обеспечивающих их доступность в сети интернет по сетевому адресу httpsː//thismywebsite·com.
+ 2.4. Информационная система персональных данных — совокупность содержащихся в базах данных персональных данных и обеспечивающих их обработку информационных технологий и технических средств.
+ 2.5. Обезличивание персональных данных — действия, в результате которых невозможно определить без использования дополнительной информации принадлежность персональных данных конкретному Пользователю или иному субъекту персональных данных.
+ 2.6. Обработка персональных данных — любое действие (операция) или совокупность действий (операций), совершаемых с использованием средств автоматизации или без использования таких средств с персональными данными, включая сбор, запись, систематизацию, накопление, хранение, уточнение (обновление, изменение), извлечение, использование, передачу (распространение, предоставление, доступ), обезличивание, блокирование, удаление, уничтожение персональных данных.
+ 2.7. Оператор — государственный орган, муниципальный орган, юридическое или физическое лицо, самостоятельно или совместно с другими лицами организующие и/или осуществляющие обработку персональных данных, а также определяющие цели обработки персональных данных, состав персональных данных, подлежащих обработке, действия (операции), совершаемые с персональными данными.
+ 2.8. Персональные данные — любая информация, относящаяся прямо или косвенно к определенному или определяемому Пользователю веб-сайта httpsː//thismywebsite·com.
+ 2.9. Персональные данные, разрешенные субъектом персональных данных для распространения, — персональные данные, доступ неограниченного круга лиц к которым предоставлен субъектом персональных данных путем дачи согласия на обработку персональных данных, разрешенных субъектом персональных данных для распространения в порядке, предусмотренном Законом о персональных данных (далее — персональные данные, разрешенные для распространения).
+ 2.10. Пользователь — любой посетитель веб-сайта httpsː//thismywebsite·com.
+ 2.11. Предоставление персональных данных — действия, направленные на раскрытие персональных данных определенному лицу или определенному кругу лиц.
+ 2.12. Распространение персональных данных — любые действия, направленные на раскрытие персональных данных неопределенному кругу лиц (передача персональных данных) или на ознакомление с персональными данными неограниченного круга лиц, в том числе обнародование персональных данных в средствах массовой информации, размещение в информационно-телекоммуникационных сетях или предоставление доступа к персональным данным каким-либо иным способом.
+ 2.13. Трансграничная передача персональных данных — передача персональных данных на территорию иностранного государства органу власти иностранного государства, иностранному физическому или иностранному юридическому лицу.
+ 2.14. Уничтожение персональных данных — любые действия, в результате которых персональные данные уничтожаются безвозвратно с невозможностью дальнейшего восстановления содержания персональных данных в информационной системе персональных данных и/или уничтожаются материальные носители персональных данных.
+ 3. Основные права и обязанности Оператора
+ 3.1. Оператор имеет право:
+ — получать от субъекта персональных данных достоверные информацию и/или документы, содержащие персональные данные;
+ — в случае отзыва субъектом персональных данных согласия на обработку персональных данных, а также, направления обращения с требованием о прекращении обработки персональных данных, Оператор вправе продолжить обработку персональных данных без согласия субъекта персональных данных при наличии оснований, указанных в Законе о персональных данных;
+ — самостоятельно определять состав и перечень мер, необходимых и достаточных для обеспечения выполнения обязанностей, предусмотренных Законом о персональных данных и принятыми в соответствии с ним нормативными правовыми актами, если иное не предусмотрено Законом о персональных данных или другими федеральными законами.
+ 3.2. Оператор обязан:
+ — предоставлять субъекту персональных данных по его просьбе информацию, касающуюся обработки его персональных данных;
+ — организовывать обработку персональных данных в порядке, установленном действующим законодательством РФ;
+ — отвечать на обращения и запросы субъектов персональных данных и их законных представителей в соответствии с требованиями Закона о персональных данных;
+ — сообщать в уполномоченный орган по защите прав субъектов персональных данных по запросу этого органа необходимую информацию в течение 10 дней с даты получения такого запроса;
+ — публиковать или иным образом обеспечивать неограниченный доступ к настоящей Политике в отношении обработки персональных данных;
+ — принимать правовые, организационные и технические меры для защиты персональных данных от неправомерного или случайного доступа к ним, уничтожения, изменения, блокирования, копирования, предоставления, распространения персональных данных, а также от иных неправомерных действий в отношении персональных данных;
+ — прекратить передачу (распространение, предоставление, доступ) персональных данных, прекратить обработку и уничтожить персональные данные в порядке и случаях, предусмотренных Законом о персональных данных;
+ — исполнять иные обязанности, предусмотренные Законом о персональных данных.
+ 4. Основные права и обязанности субъектов персональных данных
+ 4.1. Субъекты персональных данных имеют право:
+ — получать информацию, касающуюся обработки его персональных данных, за исключением случаев, предусмотренных федеральными законами. Сведения предоставляются субъекту персональных данных Оператором в доступной форме, и в них не должны содержаться персональные данные, относящиеся к другим субъектам персональных данных, за исключением случаев, когда имеются законные основания для раскрытия таких персональных данных. Перечень информации и порядок ее получения установлен Законом о персональных данных;
+ — требовать от оператора уточнения его персональных данных, их блокирования или уничтожения в случае, если персональные данные являются неполными, устаревшими, неточными, незаконно полученными или не являются необходимыми для заявленной цели обработки, а также принимать предусмотренные законом меры по защите своих прав;
+ — выдвигать условие предварительного согласия при обработке персональных данных в целях продвижения на рынке товаров, работ и услуг;
+ — на отзыв согласия на обработку персональных данных, а также, на направление требования о прекращении обработки персональных данных;
+ — обжаловать в уполномоченный орган по защите прав субъектов персональных данных или в судебном порядке неправомерные действия или бездействие Оператора при обработке его персональных данных;
+ — на осуществление иных прав, предусмотренных законодательством РФ.
+ 4.2. Субъекты персональных данных обязаны:
+ — предоставлять Оператору достоверные данные о себе;
+ — сообщать Оператору об уточнении (обновлении, изменении) своих персональных данных.
+ 4.3. Лица, передавшие Оператору недостоверные сведения о себе, либо сведения о другом субъекте персональных данных без согласия последнего, несут ответственность в соответствии с законодательством РФ.
+ 5. Принципы обработки персональных данных
+ 5.1. Обработка персональных данных осуществляется на законной и справедливой основе.
+ 5.2. Обработка персональных данных ограничивается достижением конкретных, заранее определенных и законных целей. Не допускается обработка персональных данных, несовместимая с целями сбора персональных данных.
+ 5.3. Не допускается объединение баз данных, содержащих персональные данные, обработка которых осуществляется в целях, несовместимых между собой.
+ 5.4. Обработке подлежат только персональные данные, которые отвечают целям их обработки.
+ 5.5. Содержание и объем обрабатываемых персональных данных соответствуют заявленным целям обработки. Не допускается избыточность обрабатываемых персональных данных по отношению к заявленным целям их обработки.
+ 5.6. При обработке персональных данных обеспечивается точность персональных данных, их достаточность, а в необходимых случаях и актуальность по отношению к целям обработки персональных данных. Оператор принимает необходимые меры и/или обеспечивает их принятие по удалению или уточнению неполных или неточных данных.
+ 5.7. Хранение персональных данных осуществляется в форме, позволяющей определить субъекта персональных данных, не дольше, чем этого требуют цели обработки персональных данных, если срок хранения персональных данных не установлен федеральным законом, договором, стороной которого, выгодоприобретателем или поручителем по которому является субъект персональных данных. Обрабатываемые персональные данные уничтожаются либо обезличиваются по достижении целей обработки или в случае утраты необходимости в достижении этих целей, если иное не предусмотрено федеральным законом.
+ 6. Цели обработки персональных данных
+ Цель обработки информирование Пользователя посредством отправки электронных писем
+ Персональные данные
+ философские убеждения
+ Правовые основания
+ Федеральный закон «Об информации, информационных технологиях и о защите информации» от 27.07.2006 N 149-ФЗ
+ Виды обработки персональных данных
+ Передача персональных данных
+ 7. Условия обработки персональных данных
+ 7.1. Обработка персональных данных осуществляется с согласия субъекта персональных данных на обработку его персональных данных. + 7.2. Обработка персональных данных необходима для достижения целей, предусмотренных международным договором Российской Федерации или законом, для осуществления возложенных законодательством Российской Федерации на оператора функций, полномочий и обязанностей.
+ 7.3. Обработка персональных данных необходима для осуществления правосудия, исполнения судебного акта, акта другого органа или должностного лица, подлежащих исполнению в соответствии с законодательством Российской Федерации об исполнительном производстве.
+ 7.4. Обработка персональных данных необходима для исполнения договора, стороной которого либо выгодоприобретателем или поручителем по которому является субъект персональных данных, а также для заключения договора по инициативе субъекта персональных данных или договора, по которому субъект персональных данных будет являться выгодоприобретателем или поручителем.
+ 7.5. Обработка персональных данных необходима для осуществления прав и законных интересов оператора или третьих лиц либо для достижения общественно значимых целей при условии, что при этом не нарушаются права и свободы субъекта персональных данных.
+ 7.6. Осуществляется обработка персональных данных, доступ неограниченного круга лиц к которым предоставлен субъектом персональных данных либо по его просьбе (далее — общедоступные персональные данные).
+ 7.7. Осуществляется обработка персональных данных, подлежащих опубликованию или обязательному раскрытию в соответствии с федеральным законом.
+ 8. Порядок сбора, хранения, передачи и других видов обработки персональных данных
+ Безопасность персональных данных, которые обрабатываются Оператором, обеспечивается путем реализации правовых, организационных и технических мер, необходимых для выполнения в полном объеме требований действующего законодательства в области защиты персональных данных.
+ 8.1. Оператор обеспечивает сохранность персональных данных и принимает все возможные меры, исключающие доступ к персональным данным неуполномоченных лиц.
+ 8.2. Персональные данные Пользователя никогда, ни при каких условиях не будут переданы третьим лицам, за исключением случаев, связанных с исполнением действующего законодательства либо в случае, если субъектом персональных данных дано согласие Оператору на передачу данных третьему лицу для исполнения обязательств по гражданско-правовому договору.
+ 8.3. В случае выявления неточностей в персональных данных, Пользователь может актуализировать их самостоятельно, путем направления Оператору уведомление на адрес электронной почты Оператора privacy@thismywebsite·com с пометкой «Актуализация персональных данных».
+ 8.4. Срок обработки персональных данных определяется достижением целей, для которых были собраны персональные данные, если иной срок не предусмотрен договором или действующим законодательством.
+ Пользователь может в любой момент отозвать свое согласие на обработку персональных данных, направив Оператору уведомление посредством электронной почты на электронный адрес Оператора privacy@thismywebsite·com с пометкой «Отзыв согласия на обработку персональных данных».
+ 8.5. Вся информация, которая собирается сторонними сервисами, в том числе платежными системами, средствами связи и другими поставщиками услуг, хранится и обрабатывается указанными лицами (Операторами) в соответствии с их Пользовательским соглашением и Политикой конфиденциальности. Субъект персональных данных и/или с указанными документами. Оператор не несет ответственность за действия третьих лиц, в том числе указанных в настоящем пункте поставщиков услуг.
+ 8.6. Установленные субъектом персональных данных запреты на передачу (кроме предоставления доступа), а также на обработку или условия обработки (кроме получения доступа) персональных данных, разрешенных для распространения, не действуют в случаях обработки персональных данных в государственных, общественных и иных публичных интересах, определенных законодательством РФ.
+ 8.7. Оператор при обработке персональных данных обеспечивает конфиденциальность персональных данных.
+ 8.8. Оператор осуществляет хранение персональных данных в форме, позволяющей определить субъекта персональных данных, не дольше, чем этого требуют цели обработки персональных данных, если срок хранения персональных данных не установлен федеральным законом, договором, стороной которого, выгодоприобретателем или поручителем по которому является субъект персональных данных.
+ 8.9. Условием прекращения обработки персональных данных может являться достижение целей обработки персональных данных, истечение срока действия согласия субъекта персональных данных, отзыв согласия субъектом персональных данных или требование о прекращении обработки персональных данных, а также выявление неправомерной обработки персональных данных.
+ 9. Перечень действий, производимых Оператором с полученными персональными данными
+ 9.1. Оператор осуществляет сбор, запись, систематизацию, накопление, хранение, уточнение (обновление, изменение), извлечение, использование, передачу (распространение, предоставление, доступ), обезличивание, блокирование, удаление и уничтожение персональных данных.
+ 9.2. Оператор осуществляет автоматизированную обработку персональных данных с получением и/или передачей полученной информации по информационно-телекоммуникационным сетям или без таковой.
+ 10. Трансграничная передача персональных данных
+ 10.1. Оператор до начала осуществления деятельности по трансграничной передаче персональных данных обязан уведомить уполномоченный орган по защите прав субъектов персональных данных о своем намерении осуществлять трансграничную передачу персональных данных (такое уведомление направляется отдельно от уведомления о намерении осуществлять обработку персональных данных).
+ 10.2. Оператор до подачи вышеуказанного уведомления, обязан получить от органов власти иностранного государства, иностранных физических лиц, иностранных юридических лиц, которым планируется трансграничная передача персональных данных, соответствующие сведения.
+ 11. Конфиденциальность персональных данных
+ Оператор и иные лица, получившие доступ к персональным данным, обязаны не раскрывать третьим лицам и не распространять персональные данные без согласия субъекта персональных данных, если иное не предусмотрено федеральным законом.
+ 12. Заключительные положения
+ 12.1. Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты privacy@thismywebsite·com.
+ 12.2. В данном документе будут отражены любые изменения политики обработки персональных данных Оператором. Политика действует бессрочно до замены ее новой версией.
+ 12.3. Актуальная версия Политики в свободном доступе расположена в сети Интернет по адресу httpsː//thismywebsite·com/privacy/.
+
+
+
+ + ) +} \ No newline at end of file @@ -0,0 +1,29 @@ +.container { + background-color: black; + display: grid; + justify-content: center; + color: azure; +} + +.mainInfo{ + display: grid; + background-color: rgb(41, 41, 41); + width: 85vw; + padding: 3rem; + border: 2px solid rgb(255, 255, 255); + text-align: justify; + gap: 2rem; + margin-top: 10vw; + margin-bottom: 10vw; +} + +.heading{ + font-family: "Orbitron", sans-serif; + font-size: 3rem; +} + +.content{ + font-family: "Didact Gothic", sans-serif; + font-size: 1.2rem; + line-height: 1.8; +} \ No newline at end of file @@ -0,0 +1,9 @@ +import DataProfile from "../../components/DataProfile/DataProfile" + +export default function Profile(){ + return( +
+ +
+ ) +} \ No newline at end of file @@ -0,0 +1,64 @@ +import styles from './UserAgreement.module.css' + +export default function PrivacyPolicy(){ + return( + <> +
+
+ Пользовательское соглашение +
+ 1. Общие положения Пользовательского соглашения
+ 1.1. В настоящем документе и вытекающих или связанным с ним отношениях Сторон применяются следующие термины и определения:
+
+ а) Платформа — программно-аппаратные средства, интегрированные с Сайтом Администрации;
+
+ б) Пользователь — дееспособное физическое лицо, присоединившееся к настоящему Соглашению в собственном интересе либо выступающее от имени и в интересах представляемого им юридического лица.
+
+ в) Сайт Администрации/ Сайт — интернет-сайты, размещенные в домене ________.ru и его поддоменах.
+
+ г) Сервис — комплекс услуг и лицензия, предоставляемые Пользователю с использованием Платформы.
+
+ д) Соглашение - настоящее соглашение со всеми дополнениями и изменениями.
+ 1.2. Использование вами Сервиса любым способом и в любой форме в пределах его объявленных функциональных возможностей, включая:
+
+ просмотр размещенных на Сайте материалов;
+ регистрация и/или авторизация на Сайте,
+ размещение или отображение на Сайте любых материалов, включая но не ограничиваясь такими как: тексты, гипертекстовые ссылки, изображения, аудио и видео- файлы, сведения и/или иная информация,
+ создает договор на условиях настоящего Соглашения в соответствии с положениями ст.437 и 438 Гражданского кодекса Российской Федерации.
+
+ 1.3. Воспользовавшись любой из указанных выше возможностей по использованию Сервиса вы подтверждаете, что:
+
+ а) Ознакомились с условиями настоящего Соглашения в полном объеме до начала использования Сервиса.
+
+ б) Принимаете все условия настоящего Соглашения в полном объеме без каких-либо изъятий и ограничений с вашей стороны и обязуетесь их соблюдать или прекратить использование Сервиса. Если вы не согласны с условиями настоящего Соглашения или не имеете права на заключение договора на их основе, вам следует незамедлительно прекратить любое использование Сервиса.
+
+ в) Соглашение (в том числе любая из его частей) может быть изменено Администрацией без какого-либо специального уведомления. Новая редакция Соглашения вступает в силу с момента ее размещения на Сайте Администрации либо доведения до сведения Пользователя в иной удобной форме, если иное не предусмотрено новой редакцией Соглашения.
+ 2. Условия пользования по Соглашению
+ 2.1. Использование функциональных возможностей Сервиса допускается только после прохождения Пользователем регистрации и авторизации на Сайте в соответствии с установленной Администрацией процедурой.
+
+ 2.2. Технические, организационные и коммерческие условия использования Сервиса, в том числе его функциональных возможностей доводятся до сведения Пользователей путем отдельного размещения на Сайте или путем нотификации Пользователей.
+ 2.3. Выбранные Пользователем логин и пароль являются необходимой и достаточной информацией для доступа Пользователя на Сайт. Пользователь не имеет права передавать свои логин и пароль третьим лицам, несет полную ответственность за их сохранность, самостоятельно выбирая способ их хранения.
+
+ 3. Лицензия на использование Сайта и допустимое использование Сервиса
+ В данном разеле описываются разрешенные способы использования Сайта и предоставляемого на его основе Сервиса. Безвозмездность лицензии препятствует применению Закона О защите прав потребителя в случае, когда на стороне пользователя – физическое лицо.
+
+ 4. Гарантии Пользователя по Соглашению
+ В разеле указываются гарантии и заверения со стороны пользователя о соблюдении требований законодательства и Пользовательского соглашения при использовании Сайта и Сервиса на его основе. Данные положения необходимы, в частности, для последующего возложения ответственности на пользователя за нарушения законодателства или прав третьих лиц в связи с публикацией на сайте противоправных материалов.
+
+ 5. Лицензия на использование пользовательского контента
+ При организации социального сервиса или платформы для размещения пользователями различных материалов в публичном доступе необходимо оформлять лицензионное соглашение с каждым пользователем на использование его материалов в рамках такого Интернет-сервиса. Например разрешение пользователя на использование его фотографиии может понадобиться для ее публикации на страницах других пользователей и т.д.
+
+ Кроме того, получение лицензии подтверждает факт использования контента с разрешения пользователя, который отвечает за наличие у него полномочий на выдачу такой лицензии
+ 6. Ограничения использования
+ В Пользовательском соглашении необходимо с достаточной ясностью изложить условия об ограничении ответственности за предоставление и использование Сервиса, в том числе публикуемый с его использованием пользовательский контент.
+ Помимо этого, соблюдение требований федерального закона Об информации в редакции нового антипиратского закона предполагает удаление информационным посредником спорных материалов по первому обращению правообладателя. Поэтому Пользовательское соглашение должно предоставлять владельцу интернет-сервиса такую возможность без предварительного согласования и уведомления пользователя
+ 7. Уведомления и рассылка
+ Данное положение Соглашения направлено на соблюдение требований о недопущении СПАМа.
+ 8. Условия использования аналога собственноручной подписи
+ Раздел включает порядок использования логина и пароля или адреса электронной почты в качестве ключа простой электронной подписи. Данное условие необходимо для придания юридической силы всем действиям сторон и упрощения возможного документооборота.
+
+
+
+ + ) +} \ No newline at end of file @@ -0,0 +1,29 @@ +.container { + background-color: black; + display: grid; + justify-content: center; + color: azure; +} + +.mainInfo{ + display: grid; + background-color: rgb(41, 41, 41); + width: 85vw; + padding: 3rem; + border: 2px solid rgb(255, 255, 255); + text-align: justify; + gap: 2rem; + margin-top: 10vw; + margin-bottom: 10vw; +} + +.heading{ + font-family: "Orbitron", sans-serif; + font-size: 3rem; +} + +.content{ + font-family: "Didact Gothic", sans-serif; + font-size: 1.2rem; + line-height: 1.8; +} \ No newline at end of file @@ -0,0 +1,55 @@ +@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Didact+Gothic&display=swap"); + +.orbitron { + font-family: "Orbitron", sans-serif; + font-optical-sizing: auto; + font-weight: weight; + font-style: normal; +} + +.didact-gothic-regular { + font-family: "Didact Gothic", sans-serif; + font-weight: 400; + font-style: normal; +} + +* { + margin: 0; + box-sizing: border-box; +} + +html { + font-size: 16px; + width: 100%; +} + +@media (max-width: 1920px) { + html { + font-size: 16px; + } +} + +@media (max-width: 1680px) { + html { + font-size: 12.38px; + } +} + +@media (max-width: 1440px) { + html { + font-size: 10px; + } +} + +@media (max-width: 1080px) { + html { + font-size: 8px; + } +} + +@media (max-width: 720px) { + html { + font-size: 5px; + } +} @@ -0,0 +1,59 @@ +import "./App.css"; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import Home from './pages/Home/Home'; +import Catalog from './pages/Catalog/Catalog'; +import Error from './pages/Error/Error'; +import Login from './pages/Auth/Login/Login'; +import Registration from './pages/Auth/Registration/Registration'; +import About from './pages/About/About'; +import Profile from "./pages/Profile/Profile"; +import Basket from "./pages/Basket/Basket"; +import Header from "./components/Header/Header"; +import Footer from "./components/Footer/Footer"; +import PrivacyPolicy from './pages/PrivacyPolicy/PrivacyPolicy' +import UserAgreement from './pages/UserAgreement/UserAgreement' +import { useFooter } from './hooks/useFooter'; +import { CartProvider } from "./components/CartContext"; +import { guestNavItems } from "./components/projectConstants"; +import { authNavItems } from "./components/projectConstants"; +import { footerSections } from "./components/projectConstants"; +import { useAuth } from "./hooks/useAuth"; + +function AppContent() { + const showFooter = useFooter(); + + return ( + <> +
+
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+ {showFooter &&