@@ -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
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
@@ -0,0 +1,221 @@
+import { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useCart } from '../../hooks/UseCart.js';
+import CartItem from './CartItem.jsx';
+import CheckboxInput from './CheckboxInput.jsx';
+import SummaryRow from './SummaryRow.jsx';
+import styles from "./BasketMain.module.css";
+import toast from 'react-hot-toast';
+
+export default function BasketMain() {
+ const navigate = useNavigate();
+ const [agreements, setAgreements] = useState({
+ newsletter: false,
+ personalData: false,
+ privacyPolicy: false
+ });
+ const [user, setUser] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const {
+ cart,
+ removeFromCart,
+ updateQuantity,
+ clearCart,
+ calculateTotal,
+ calculateItemsCount
+ } = useCart();
+
+ useEffect(() => {
+ const loadUser = () => {
+ try {
+ const savedUser = localStorage.getItem('currentUser');
+ if (savedUser) {
+ setUser(JSON.parse(savedUser));
+ } else {
+ navigate('/login');
+ }
+ } catch (error) {
+ navigate('/login');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ loadUser();
+ }, [navigate]);
+
+ const handleAgreementChange = (name) => {
+ setAgreements(prev => ({ ...prev, [name]: !prev[name] }));
+ };
+
+ const handleCheckout = () => {
+ if (!agreements.personalData || !agreements.privacyPolicy) {
+ toast('Примите соглашения для оформления заказа');
+ return;
+ }
+
+ if (cart.length === 0) {
+ toast('Корзина пуста');
+ return;
+ }
+
+ const orderData = {
+ orderId: Date.now(),
+ userId: user?.id || user?.email,
+ userName: user?.fullName || user?.email,
+ items: cart,
+ totalAmount: calculateTotal(),
+ email: user?.email,
+ orderDate: new Date().toISOString(),
+ status: 'pending'
+ };
+
+ const existingOrders = JSON.parse(localStorage.getItem('orders') || '[]');
+ localStorage.setItem('orders', JSON.stringify([...existingOrders, orderData]));
+
+ toast(`Заказ #${orderData.orderId} оформлен на сумму $${calculateTotal()}`);
+ clearCart();
+ navigate('/basket');
+ };
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ if (!user) {
+ return null;
+ }
+
+ if (cart.length === 0) {
+ return (
+
+
+
Корзина пуста
+
+ Добавьте товары из каталога, чтобы сделать заказ
+
+
navigate('/catalog')}
+ className={styles.continueShopping}
+ >
+ Перейти в каталог
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
Корзина
+
+ Покупатель: {user.fullName || user.email}
+ Email: {user.email}
+
+
+
+
+
+ Ваш заказ ({calculateItemsCount()} товаров)
+
+
+
window.confirm('Очистить корзину?') && clearCart()}
+ className={styles.clearCartButton}
+ >
+ Очистить корзину
+
+
+
+
+ {cart.map(item => (
+ updateQuantity(item.id, quantity)}
+ onRemove={() => removeFromCart(item.id)}
+ />
+ ))}
+
+
+
+
Сводка заказа
+
+
+
+
+
+
+
+
+
Соглашения
+
+
+ handleAgreementChange('newsletter')}
+ label="Получать рекламную информацию от prime"
+ />
+
+ handleAgreementChange('personalData')}
+ label="Я соглашаюсь с условиями обработки персональных данных"
+ required={true}
+ />
+
+ handleAgreementChange('privacyPolicy')}
+ label="Я соглашаюсь с политикой конфиденциальности"
+ required={true}
+ />
+
+
+
* Обязательные поля
+
+
+
+
+ К оплате:
+ ${calculateTotal().toLocaleString()}
+
+
+
+ {!agreements.personalData || !agreements.privacyPolicy
+ ? 'Примите соглашения'
+ : `Оформить заказ за $${calculateTotal().toLocaleString()}`
+ }
+
+
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,696 @@
+.body {
+ min-height: 100vh;
+ background-color: #000000;
+ margin: 0;
+ padding: 0;
+}
+
+.container {
+ font-family: "Orbitron", sans-serif;
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+ display: grid;
+ gap: 20px;
+ min-height: 100vh;
+}
+
+.loading {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 300px;
+}
+
+.loadingSpinner {
+ width: 50px;
+ height: 50px;
+ border: 5px solid #f3f3f3;
+ border-top: 5px solid #3498db;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+ margin-bottom: 20px;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+.userInfo {
+ background: rgb(0, 0, 0);
+ padding: 15px 20px;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ display: flex;
+ justify-content: space-between;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+
+.userInfo span {
+ font-size: 14px;
+ color: #ffffff;
+}
+
+.userInfo strong {
+ color: #ffffff;
+ margin-left: 5px;
+}
+
+.title {
+ font-size: 32px;
+ font-weight: bold;
+ text-align: center;
+ margin-bottom: 30px;
+ color: #ffffff;
+}
+
+.cartHeader {
+ font-family: "Orbitron", sans-serif;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ padding-bottom: 15px;
+ border-bottom: 2px solid #e0e0e0;
+}
+
+.cartTitle {
+ font-size: 20px;
+ font-weight: 600;
+ color: #ffffff;
+ margin: 0;
+}
+
+.clearCartButton {
+ padding: 8px 16px;
+ background-color: #ff6b6b;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: background-color 0.3s;
+}
+
+.clearCartButton:hover {
+ background-color: #ff5252;
+}
+
+.cartItems {
+ font-family: "Orbitron", sans-serif;
+ background: rgb(0, 0, 0);
+ border-radius: 10px;
+ padding: 20px;
+ margin-bottom: 30px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+
+.cartItem {
+ font-family: "Orbitron", sans-serif;
+ display: flex;
+ align-items: center;
+ padding: 15px 0;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.cartItem:last-child {
+ border-bottom: none;
+}
+
+.itemImage {
+ width: 100px;
+ height: 100px;
+ margin-right: 20px;
+ flex-shrink: 0;
+}
+
+.itemImage img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 8px;
+}
+
+.itemInfo {
+ flex: 1;
+ min-width: 0;
+}
+
+.itemTitle {
+ font-family: "Orbitron", sans-serif;
+ font-size: 18px;
+ font-weight: 600;
+ margin: 0 0 10px 0;
+ color: #ffffff;
+ word-wrap: break-word;
+}
+
+.itemDescription {
+ font-size: 14px;
+ color: #ffffff;
+ margin: 0 0 10px 0;
+ line-height: 1.4;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.itemPrice {
+ font-size: 16px;
+ font-weight: 600;
+ color: #4c77af;
+ display: block;
+ margin-bottom: 10px;
+}
+
+.itemControls {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ flex-wrap: wrap;
+}
+
+.quantityControl {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.quantityButton {
+ width: 30px;
+ height: 30px;
+ background: #000000;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 18px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: background 0.3s;
+}
+
+.quantityButton:hover {
+ background: #e0e0e0;
+}
+
+.quantity {
+ font-size: 18px;
+ font-weight: 600;
+ min-width: 30px;
+ text-align: center;
+}
+
+.itemTotal {
+ font-size: 20px;
+ font-weight: 700;
+ color: #ffffff;
+ min-width: 80px;
+ text-align: right;
+}
+
+.removeButton {
+ width: 30px;
+ height: 30px;
+ background: #b0bce4;
+ color: white;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ font-size: 18px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: background-color 0.3s;
+}
+
+.removeButton:hover {
+ background: #232c7e;
+}
+
+.orderSummary {
+ background: white;
+ border-radius: 10px;
+ padding: 25px;
+ margin-bottom: 30px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+
+.summaryRow {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 0;
+ font-size: 16px;
+ color: #ffffff;
+}
+
+.summaryDivider {
+ height: 1px;
+ background: #e0e0e0;
+ margin: 15px 0;
+}
+
+.totalAmount {
+ font-size: 24px;
+ color: #0d1539;
+}
+
+.agreementsSection {
+ background: white;
+ border-radius: 10px;
+ padding: 25px;
+ margin-bottom: 30px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+
+.agreementsTitle {
+ font-size: 20px;
+ font-weight: 600;
+ margin-bottom: 20px;
+ color: #ffffff;
+}
+
+.agreementItem {
+ margin-bottom: 15px;
+}
+
+.checkboxLabel {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ font-size: 16px;
+ color: #fffdfd;
+ cursor: pointer;
+ line-height: 1.4;
+}
+
+.checkbox {
+ width: 18px;
+ height: 18px;
+ cursor: pointer;
+ accent-color: #121f56;
+ margin-top: 3px;
+ flex-shrink: 0;
+}
+
+.requiredNote {
+ font-size: 14px;
+ color: #ffffff;
+ margin-top: 15px;
+ font-style: italic;
+ display: flex;
+ padding-bottom: 20px;
+}
+
+.checkout {
+ border-radius: 10px;
+ padding: 25px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-top: 3rem;
+ background: rgb(0, 0, 0);
+}
+
+.checkboxContainer {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ padding-bottom: 20px;
+ border-bottom: 2px solid #e0e0e0;
+ gap: 20px;
+ flex-wrap: wrap;
+}
+
+.checkoutTotal {
+ font-size: 20px;
+ font-weight: 600;
+ color: #ffffff;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ flex-wrap: wrap;
+}
+
+.checkoutTotalAmount {
+ font-size: 32px;
+ font-weight: 800;
+ color: #2b239c;
+}
+
+.checkoutButton {
+ padding: 16px 40px;
+ background: #2b239c;
+ color: white;
+ border: none;
+ border-radius: 8px;
+ font-size: 18px;
+ font-weight: 700;
+ cursor: pointer;
+ width: 100%;
+ max-width: 400px;
+ transition: all 0.3s;
+ white-space: nowrap;
+}
+
+.checkoutButton:hover:not(:disabled) {
+ background: #2b239c;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 15px rgba(43, 35, 156, 0.3);
+}
+
+.checkoutButton:disabled {
+ background: #cccccc;
+ cursor: not-allowed;
+ transform: none;
+ box-shadow: none;
+}
+
+.continueShoppingLink {
+ color: #2196F3;
+ text-decoration: none;
+ font-size: 16px;
+ transition: color 0.2s;
+}
+
+.continueShoppingLink:hover {
+ color: #0b7dda;
+ text-decoration: underline;
+}
+
+.emptyCart {
+ font-family: "Orbitron", sans-serif;
+ text-align: center;
+ padding: 60px 20px;
+ max-width: 500px;
+ margin: 0 auto;
+ padding-top: 30vh;
+}
+
+.emptyCartIcon {
+ font-size: 80px;
+ margin-bottom: 20px;
+ opacity: 0.3;
+}
+
+.emptyCartTitle {
+ font-size: 28px;
+ font-weight: 600;
+ margin-bottom: 15px;
+ color: #ffffff;
+}
+
+.emptyCartText {
+ font-size: 16px;
+ color: #ffffff;
+ margin-bottom: 30px;
+ line-height: 1.5;
+}
+
+.continueShopping {
+ display: inline-block;
+ padding: 12px 30px;
+ background: #2196F3;
+ color: white;
+ text-decoration: none;
+ border-radius: 6px;
+ font-weight: 600;
+ transition: background 0.3s;
+}
+
+.continueShopping:hover {
+ background: #0b7dda;
+}
+
+
+@media (min-width: 1440px) {
+ .container {
+ max-width: 1400px;
+ padding: 40px;
+ }
+
+ .title {
+ font-size: 36px;
+ }
+}
+
+@media (max-width: 1199px) {
+ .container {
+ max-width: 100%;
+ padding: 20px;
+ }
+
+ .cartItem {
+ flex-wrap: wrap;
+ }
+
+ .itemInfo {
+ flex-basis: calc(100% - 120px);
+ }
+}
+
+@media (max-width: 1023px) {
+ .title {
+ font-size: 28px;
+ margin-bottom: 20px;
+ }
+
+ .cartHeader {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+ }
+
+ .cartItem {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+ }
+
+ .itemImage {
+ width: 100%;
+ height: 200px;
+ margin-right: 0;
+ }
+
+ .itemControls {
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ .checkout {
+ flex-direction: column;
+ gap: 20px;
+ align-items: stretch;
+ }
+
+ .checkoutTotal {
+ justify-content: space-between;
+ }
+
+ .checkoutButton {
+ max-width: 100%;
+ }
+
+ .emptyCart {
+ padding-top: 20vh;
+ }
+}
+
+@media (max-width: 767px) {
+ .container {
+ padding: 15px;
+ gap: 15px;
+ }
+
+ .title {
+ font-size: 24px;
+ }
+
+ .userInfo {
+ flex-direction: column;
+ gap: 10px;
+ padding: 15px;
+ }
+
+ .cartTitle {
+ font-size: 18px;
+ }
+
+ .cartItems,
+ .orderSummary,
+ .agreementsSection,
+ .checkout {
+ padding: 15px;
+ }
+
+ .itemTitle {
+ font-size: 16px;
+ }
+
+ .itemPrice,
+ .itemTotal {
+ font-size: 16px;
+ }
+
+ .summaryRow {
+ font-size: 14px;
+ }
+
+ .totalAmount {
+ font-size: 20px;
+ }
+
+ .agreementsTitle {
+ font-size: 18px;
+ }
+
+ .checkboxLabel {
+ font-size: 14px;
+ }
+
+ .checkoutTotal {
+ flex-direction: column;
+ gap: 10px;
+ text-align: center;
+ }
+
+ .checkoutTotalAmount {
+ font-size: 28px;
+ }
+
+ .checkoutButton {
+ padding: 14px 20px;
+ font-size: 16px;
+ }
+
+ .emptyCartTitle {
+ font-size: 22px;
+ }
+
+ .emptyCartIcon {
+ font-size: 60px;
+ }
+}
+
+@media (max-width: 575px) {
+ .container {
+ padding: 10px;
+ gap: 10px;
+ }
+
+ .title {
+ font-size: 20px;
+ margin-bottom: 15px;
+ }
+
+ .cartHeader {
+ gap: 10px;
+ }
+
+ .clearCartButton {
+ padding: 6px 12px;
+ font-size: 13px;
+ }
+
+ .itemDescription {
+ -webkit-line-clamp: 3;
+ }
+
+ .itemControls {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+ }
+
+ .quantityControl {
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ .removeButton {
+ align-self: flex-end;
+ }
+
+ .checkboxContainer {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+ }
+
+ .checkoutTotal {
+ width: 100%;
+ }
+
+ .emptyCart {
+ padding: 40px 15px;
+ padding-top: 15vh;
+ }
+
+ .emptyCartTitle {
+ font-size: 20px;
+ }
+
+ .emptyCartText {
+ font-size: 14px;
+ }
+
+ .continueShopping {
+ padding: 10px 20px;
+ font-size: 14px;
+ }
+}
+
+@media (max-width: 320px) {
+ .container {
+ padding: 8px;
+ }
+
+ .title {
+ font-size: 18px;
+ }
+
+ .cartTitle {
+ font-size: 16px;
+ }
+
+ .itemImage {
+ height: 150px;
+ }
+
+ .checkoutTotalAmount {
+ font-size: 24px;
+ }
+
+ .checkoutButton {
+ font-size: 14px;
+ padding: 12px 16px;
+ }
+}
+
+@media (max-width: 1440px) and (min-width: 1200px) {
+ .container {
+ max-width: 1100px;
+ }
+}
+
+@media (max-width: 767px) {
+ .body {
+ overflow-x: hidden;
+ }
+
+ .container {
+ overflow-x: hidden;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ }
+}
+
@@ -0,0 +1,39 @@
+import styles from "./BasketMain.module.css";
+
+export default function CartItem({ item, onRemove }){
+ return (
+
+
+
{
+ e.target.src = 'https://via.placeholder.com/150x150?text=No+Image';
+ }}
+ />
+
+
+
{item.title}
+
{item.description}
+
Цена: ${item.price}
+
+
+
+ {item.quantity}
+
+
+ ${(item.price * item.quantity).toLocaleString()}
+
+
{
+ onRemove(item.id);
+ }}
+ aria-label="Удалить товар"
+ >
+ ✕
+
+
+
+ );
+};
\ No newline at end of file
@@ -0,0 +1,30 @@
+import styles from './BasketMain.module.css';
+export default function CheckboxInput({
+ id,
+ name,
+ checked,
+ onChange,
+ label,
+ required = false,
+ className = '',
+ ...props
+}) {
+ return (
+
+
+
+ {label}
+ {required && * }
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,74 @@
+import { useState, useEffect } from 'react';
+import styles from './BasketMain.module.css';
+
+export default function QuantityControl({
+ quantity,
+ onChange,
+ min = 1,
+ max = 99,
+ className = ''
+}) {
+ const [localQuantity, setLocalQuantity] = useState(quantity);
+
+ useEffect(() => {
+ setLocalQuantity(quantity);
+ }, [quantity]);
+
+ const handleIncrement = () => {
+ if (localQuantity < max) {
+ const newQuantity = localQuantity + 1;
+ setLocalQuantity(newQuantity);
+ onChange(newQuantity);
+ }
+ };
+
+ const handleDecrement = () => {
+ if (localQuantity > min) {
+ const newQuantity = localQuantity - 1;
+ setLocalQuantity(newQuantity);
+ onChange(newQuantity);
+ }
+ };
+
+ const handleManualChange = (e) => {
+ const value = parseInt(e.target.value);
+ if (!isNaN(value) && value >= min && value <= max) {
+ setLocalQuantity(value);
+ onChange(value);
+ }
+ };
+
+ return (
+
+
+ −
+
+
+
+
+ = max}
+ aria-label="Увеличить количество"
+ >
+ +
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,20 @@
+import styles from './BasketMain.module.css';
+
+export default function SummaryRow({
+ label,
+ value,
+ isTotal = false,
+ isDiscount = false,
+ className = ''
+}) {
+ return (
+
+
+ {label}
+
+
+ {value}
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,210 @@
+import { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import styles from "./Profile.module.css";
+
+export default function DataProfile() {
+ const navigate = useNavigate();
+ const [user, setUser] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [isEditing, setIsEditing] = useState(false);
+ const [editForm, setEditForm] = useState({
+ fullName: '',
+ phone: '',
+ email: ''
+ });
+
+ useEffect(() => {
+ const loadUserData = () => {
+ setIsLoading(true);
+ try {
+ const savedUser = localStorage.getItem('currentUser');
+ if (savedUser) {
+ const userData = JSON.parse(savedUser);
+ setUser(userData);
+ setEditForm({
+ fullName: userData.fullName || '',
+ phone: userData.phone || '',
+ email: userData.email || ''
+ });
+ } else {
+ navigate('/login');
+ }
+ } catch (error) {
+ console.error('Ошибка загрузки данных пользователя:', error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ loadUserData();
+ }, [navigate]);
+
+ const handleEdit = () => {
+ setIsEditing(true);
+ };
+
+ const handleCancelEdit = () => {
+ setIsEditing(false);
+ setEditForm({
+ fullName: user.fullName || '',
+ phone: user.phone || '',
+ email: user.email || ''
+ });
+ };
+
+ const handleSave = () => {
+ if (!editForm.fullName.trim() || !editForm.phone.trim() || !editForm.email.trim()) {
+ alert('Все поля обязательны для заполнения');
+ return;
+ }
+
+ const updatedUser = {
+ ...user,
+ ...editForm
+ };
+
+ setUser(updatedUser);
+ localStorage.setItem('currentUser', JSON.stringify(updatedUser));
+
+ const users = JSON.parse(localStorage.getItem('registeredUsers') || '[]');
+ const updatedUsers = users.map(u =>
+ u.email === user.email ? updatedUser : u
+ );
+ localStorage.setItem('registeredUsers', JSON.stringify(updatedUsers));
+
+ setIsEditing(false);
+ alert('Данные успешно обновлены!');
+ };
+
+ const handleLogout = () => {
+ localStorage.removeItem('currentUser');
+ navigate('/login');
+ };
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setEditForm(prev => ({
+ ...prev,
+ [name]: value
+ }));
+ };
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ if (!user) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
{user.fullName}
+
{user.email}
+
+
+
+
Личная информация
+
+ {isEditing ? (
+
+
+ ФИО
+
+
+
+
+ Email
+
+
+
+
+ Телефон
+
+
+
+
+
+ Сохранить
+
+
+ Отмена
+
+
+
+ ) : (
+ <>
+
+ ФИО:
+ {user.fullName}
+
+
+
+ Email:
+ {user.email}
+
+
+
+ Телефон:
+ {user.phone}
+
+
+
+ Дата регистрации:
+
+ {user.registeredAt ? new Date(user.registeredAt).toLocaleDateString('ru-RU') : 'Не указана'}
+
+
+
+
+
+ Редактировать профиль
+
+
+ Выйти
+
+
+ >
+ )}
+
+
+
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,585 @@
+.body {
+ min-height: 100vh;
+ background-color: #000000;
+ margin: 0;
+ padding: 0;
+ overflow-x: hidden;
+}
+
+.profileContainer {
+ font-family: "Orbitron", sans-serif;
+ display: grid;
+ width: 100%;
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ box-sizing: border-box;
+ margin-top: 10rem;
+ padding-bottom: 7rem;
+}
+
+.profileTitle {
+ font-size: 2rem;
+ font-weight: bold;
+ text-align: center;
+ color: #333;
+ margin-bottom: 2rem;
+}
+
+.profileInfo {
+ background: rgb(86, 89, 100);
+ border-radius: 12px;
+ padding: 2rem;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.avatarSection {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ margin-bottom: 2rem;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid #eee;
+}
+
+.avatar {
+ width: 150px;
+ height: 150px;
+ border-radius: 50%;
+ object-fit: cover;
+ margin: 0 auto 1.5rem;
+ display: block;
+ border: 4px solid #667eea;
+}
+
+.userName {
+ font-size: 1.8rem;
+ font-weight: bold;
+ margin-bottom: 0.5rem;
+ color: #f0f0f0;
+}
+
+.userEmail {
+ font-size: 1rem;
+ color: #cccccc;
+ margin-bottom: 0;
+}
+
+.infoSection {
+ width: 100%;
+ margin-top: 2rem;
+}
+
+.sectionTitle {
+ font-size: 1.5rem;
+ font-weight: 600;
+ margin-bottom: 1.5rem;
+ color: #f0f0f0;
+ padding-bottom: 1rem;
+ border-bottom: 2px solid #555;
+}
+
+.infoRow {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 0;
+ border-bottom: 1px solid #666;
+}
+
+.infoRow:last-child {
+ border-bottom: none;
+}
+
+.infoLabel {
+ font-weight: 500;
+ color: #cccccc;
+ min-width: 120px;
+}
+
+.infoValue {
+ font-weight: 400;
+ color: #ffffff;
+ text-align: right;
+ flex: 1;
+ word-break: break-word;
+}
+
+.editForm {
+ background: #1f1f1f;
+ padding: 1.5rem;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+ margin-top: 1rem;
+}
+
+.formGroup {
+ margin-bottom: 1.5rem;
+}
+
+.label {
+ display: block;
+ margin-bottom: 8px;
+ font-weight: 500;
+ color: #f8f8f8;
+}
+
+.editInput {
+ width: 100%;
+ padding: 0.75rem 1rem;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-size: 1rem;
+ transition: border-color 0.3s;
+ box-sizing: border-box;
+ background-color: #6d6d6d;
+}
+
+.editInput:focus {
+ outline: none;
+ border-color: #667eea;
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
+}
+
+.editButtons {
+ display: flex;
+ gap: 1rem;
+ margin-top: 1.5rem;
+ flex-wrap: wrap;
+}
+
+.saveButton {
+ padding: 12px 24px;
+ background: #667eea;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ font-size: 16px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s;
+ flex: 1;
+ min-width: 120px;
+}
+
+.saveButton:hover {
+ transform: translateY(-2px);
+ background: #5a6fd8;
+}
+
+.cancelButton {
+ padding: 12px 24px;
+ background: #f0f0f0;
+ color: #666;
+ border: none;
+ border-radius: 6px;
+ font-size: 16px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: background-color 0.2s;
+ flex: 1;
+ min-width: 120px;
+}
+
+.cancelButton:hover {
+ background: #e0e0e0;
+}
+
+.actionButtons {
+ display: flex;
+ gap: 1rem;
+ margin-top: 2rem;
+ flex-wrap: wrap;
+}
+
+.editButton {
+ padding: 12px 24px;
+ background: #667eea;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ font-size: 16px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s;
+ flex: 1;
+ min-width: 120px;
+}
+
+.editButton:hover {
+ background: #5a6fd8;
+ transform: translateY(-2px);
+}
+
+.logoutButton {
+ padding: 12px 24px;
+ background: #1f1a1a;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ font-size: 16px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s;
+ flex: 1;
+ min-width: 120px;
+}
+
+.logoutButton:hover {
+ background: #ff5252;
+ transform: translateY(-2px);
+}
+
+.fon {
+ margin-top: 2rem;
+ text-align: center;
+}
+
+
+@media (min-width: 1440px) {
+ .profileContainer {
+ max-width: 1400px;
+ padding: 40px;
+ }
+
+ .profileTitle {
+ font-size: 2.5rem;
+ }
+
+ .profileInfo {
+ padding: 3rem;
+ }
+}
+
+@media (max-width: 1199px) {
+ .profileContainer {
+ max-width: 100%;
+ padding: 30px;
+ }
+
+ .avatar {
+ width: 140px;
+ height: 140px;
+ }
+}
+
+@media (max-width: 1023px) {
+ .profileContainer {
+ padding: 20px;
+ margin-top: 5rem;
+ }
+
+ .profileTitle {
+ font-size: 1.8rem;
+ margin-bottom: 1.5rem;
+ }
+
+ .profileInfo {
+ padding: 1.5rem;
+ }
+
+ .avatar {
+ width: 130px;
+ height: 130px;
+ }
+
+ .userName {
+ font-size: 1.6rem;
+ }
+
+ .sectionTitle {
+ font-size: 1.3rem;
+ }
+
+ .infoRow {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ }
+
+ .infoValue {
+ text-align: left;
+ width: 100%;
+ }
+
+ .actionButtons,
+ .editButtons {
+ flex-direction: column;
+ }
+
+ .saveButton,
+ .cancelButton,
+ .editButton,
+ .logoutButton {
+ width: 100%;
+ max-width: 300px;
+ margin: 0 auto;
+ }
+}
+
+@media (max-width: 767px) {
+ .profileContainer {
+ padding: 15px;
+ margin-top: 4rem;
+ }
+
+ .profileTitle {
+ font-size: 1.6rem;
+ margin-bottom: 1rem;
+ }
+
+ .profileInfo {
+ padding: 1rem;
+ border-radius: 8px;
+ }
+
+ .avatar {
+ width: 120px;
+ height: 120px;
+ }
+
+ .userName {
+ font-size: 1.4rem;
+ }
+
+ .userEmail {
+ font-size: 0.9rem;
+ }
+
+ .sectionTitle {
+ font-size: 1.2rem;
+ margin-bottom: 1rem;
+ }
+
+ .infoLabel {
+ font-size: 0.9rem;
+ min-width: 100px;
+ }
+
+ .infoValue {
+ font-size: 0.9rem;
+ }
+
+ .editForm {
+ padding: 1rem;
+ }
+
+ .label {
+ font-size: 0.9rem;
+ }
+
+ .editInput {
+ padding: 0.6rem 0.8rem;
+ font-size: 0.9rem;
+ }
+
+ .saveButton,
+ .cancelButton,
+ .editButton,
+ .logoutButton {
+ padding: 10px 20px;
+ font-size: 14px;
+ }
+}
+
+@media (max-width: 575px) {
+ .profileContainer {
+ padding: 10px;
+ margin-top: 3rem;
+ }
+
+ .profileTitle {
+ font-size: 1.4rem;
+ }
+
+ .profileInfo {
+ padding: 0.8rem;
+ border-radius: 6px;
+ }
+
+ .avatarSection {
+ margin-bottom: 1.5rem;
+ padding-bottom: 1.5rem;
+ }
+
+ .avatar {
+ width: 100px;
+ height: 100px;
+ margin-bottom: 1rem;
+ }
+
+ .userName {
+ font-size: 1.2rem;
+ }
+
+ .userEmail {
+ font-size: 0.85rem;
+ }
+
+ .infoSection {
+ margin-top: 1.5rem;
+ }
+
+ .sectionTitle {
+ font-size: 1.1rem;
+ padding-bottom: 0.8rem;
+ margin-bottom: 0.8rem;
+ }
+
+ .infoRow {
+ padding: 8px 0;
+ }
+
+ .infoLabel {
+ font-size: 0.85rem;
+ min-width: 80px;
+ }
+
+ .infoValue {
+ font-size: 0.85rem;
+ }
+
+ .editForm {
+ padding: 0.8rem;
+ }
+
+ .formGroup {
+ margin-bottom: 1rem;
+ }
+
+ .label {
+ font-size: 0.85rem;
+ margin-bottom: 6px;
+ }
+
+ .editInput {
+ padding: 0.5rem 0.7rem;
+ font-size: 0.85rem;
+ }
+
+ .editButtons {
+ margin-top: 1rem;
+ gap: 0.5rem;
+ }
+
+ .actionButtons {
+ margin-top: 1.5rem;
+ gap: 0.5rem;
+ }
+
+ .saveButton,
+ .cancelButton,
+ .editButton,
+ .logoutButton {
+ padding: 8px 16px;
+ font-size: 13px;
+ min-width: 100px;
+ }
+}
+
+@media (max-width: 320px) {
+ .profileContainer {
+ padding: 8px;
+ margin-top: 2rem;
+ }
+
+ .profileTitle {
+ font-size: 1.2rem;
+ }
+
+ .profileInfo {
+ padding: 0.6rem;
+ }
+
+ .avatar {
+ width: 80px;
+ height: 80px;
+ }
+
+ .userName {
+ font-size: 1rem;
+ }
+
+ .sectionTitle {
+ font-size: 1rem;
+ }
+
+ .infoLabel {
+ font-size: 0.8rem;
+ min-width: 70px;
+ }
+
+ .infoValue {
+ font-size: 0.8rem;
+ }
+
+ .saveButton,
+ .cancelButton,
+ .editButton,
+ .logoutButton {
+ padding: 6px 12px;
+ font-size: 12px;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ .profileInfo {
+ background: #2d2d2d;
+ }
+
+ .userName,
+ .sectionTitle {
+ color: #ffffff;
+ }
+
+ .userEmail,
+ .infoLabel {
+ color: #cccccc;
+ }
+
+ .infoValue {
+ color: #ffffff;
+ }
+
+ .infoRow {
+ border-bottom-color: #444;
+ }
+
+ .sectionTitle {
+ border-bottom-color: #444;
+ }
+}
+
+@media (max-height: 600px) and (orientation: portrait) {
+ .profileContainer {
+ margin-top: 2rem;
+ }
+
+ .avatarSection {
+ margin-bottom: 1rem;
+ padding-bottom: 1rem;
+ }
+
+ .avatar {
+ width: 80px;
+ height: 80px;
+ }
+
+ .userName {
+ font-size: 1.2rem;
+ }
+}
+
+* {
+ box-sizing: border-box;
+}
+
+button,
+input {
+ transition: all 0.3s ease;
+}
+
+
@@ -0,0 +1,52 @@
+import styles from './Footer.module.css';
+import { Link } from 'react-router-dom';
+import { footer } from '../constants';
+
+export default function Footer() {
+ const renderLink = (link) => {
+ if (link.external) {
+ return (
+
+ {link.title}
+
+ );
+ }
+
+ return (
+
+ {link.title}
+
+ );
+ };
+
+ return (
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,52 @@
+
+.hrr{
+ border-top: 3px solid rgb(255, 255, 255);
+ padding-bottom: 3rem;
+}
+.logo {
+ font-family: "Orbitron", sans-serif;
+ font-optical-sizing: auto;
+ font-weight: weight;
+ font-style: normal;
+ font-size: 2.25rem;
+ color: #ffffff;
+ margin-top: 4.375rem;
+ margin-left: 8.0625rem;
+}
+.link{
+ display: grid;
+ width: auto;
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 1rem;
+ color: #ffffff;
+ margin-top: 3.125rem;
+ margin-left: 18.31rem;
+ text-decoration: none;
+}
+.linkSocial{
+ display: grid;
+ gap: 1rem;
+ width: auto;
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 1rem;
+ color: #ffffff;
+ margin-top: 3.125rem;
+ text-decoration: none;
+ padding-right: 7rem;
+}
+a{
+ color: #ffffff;
+ text-decoration: none;
+}
+.linkItem{
+ text-decoration: none;
+ color: #ffffff;
+}
+.linksContainer{
+ justify-content: space-between;
+ display: flex;
+ padding-bottom: 2rem;
+}
+.footer{
+ background-color: black;
+}
\ No newline at end of file
@@ -0,0 +1,71 @@
+import { Link } from 'react-router-dom';
+import { useAuth } from '../../hooks/UseAuth';
+import styles from './Header.module.css';
+import { guestNavItems } from '../constants';
+import { authNavItems } from '../constants';
+
+
+export default function Header() {
+const { isAuthenticated, isLoading } = useAuth(false);
+
+ const navItems = isAuthenticated ? authNavItems : guestNavItems;
+
+ const handleItemClick = (item, e) => {
+ if (item.isAction && item.action) {
+ e.preventDefault();
+ item.action();
+ }
+ };
+
+ if (isLoading) {
+ return (
+
+ prime
+
+ Загрузка меню...
+
+
+ );
+ }
+
+ return (
+
+ prime
+
+
+
+
+
+
+ {navItems.map((item) => (
+
+ ))}
+
+
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,472 @@
+.menuimg {
+ width: 3rem;
+ height: auto;
+ cursor: pointer;
+ transition: transform 0.3s ease;
+}
+
+.menuimg:hover {
+ transform: scale(1.1);
+}
+
+header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ margin: 0 auto;
+ padding: 1.5rem 20px;
+ box-sizing: border-box;
+ position: absolute;
+ justify-content: space-between;
+ padding-left: 8rem;
+ padding-right: 8rem;
+}
+
+.logo {
+ font-family: "Orbitron", sans-serif;
+ font-size: 2rem;
+ color: #ffffff;
+ margin: 0;
+ z-index: 1000;
+}
+
+.select {
+ width: auto;
+ cursor: pointer;
+ position: relative;
+ transition: all 0.3s ease;
+ color: rgb(218, 218, 218);
+ overflow: visible;
+ z-index: 1000;
+}
+
+.selected {
+ font-family: "Didact Gothic", sans-serif;
+ background-color: rgb(0, 0, 0);
+ padding: 0.75rem 1rem;
+ border-radius: 8px;
+ position: relative;
+ z-index: 1002;
+ font-size: 0.9rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ backdrop-filter: blur(10px);
+ border: 1px solid rgb(0, 0, 0);
+ min-width: 3.5rem;
+ min-height: 3.5rem;
+}
+
+.selected:hover {
+ background-color:rgb(0, 0, 0);
+}
+
+.arrow {
+ position: relative;
+ height: 10px;
+ transform: rotate(-90deg);
+ width: 1rem;
+ fill: rgb(176, 176, 176);
+ z-index: 1000;
+ transition: transform 0.3s ease;
+}
+
+.options {
+ display: flex;
+ flex-direction: column;
+ border-radius: 8px;
+ padding: 0.5rem;
+ background-color:rgb(0, 0, 0);
+ position: absolute;
+ top: 100%;
+ right: 0;
+ opacity: 0;
+ visibility: hidden;
+ transform: translateY(-10px);
+ transition: all 0.3s ease;
+ font-family: "Orbitron", sans-serif;
+ min-width: 12rem;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ backdrop-filter: blur(10px);
+ z-index: 1001;
+}
+
+.select:hover .options,
+.select:focus-within .options {
+ opacity: 1;
+ visibility: visible;
+ transform: translateY(0);
+}
+
+.select:hover .selected .arrow,
+.select:focus-within .selected .arrow {
+ transform: rotate(0deg);
+}
+
+.option {
+ border-radius: 6px;
+ padding: 0.75rem 1rem;
+ transition: all 0.2s ease;
+ background-color: transparent;
+ font-size: 0.9rem;
+ text-align: left;
+ cursor: pointer;
+ text-decoration: none;
+ display: block;
+ color: #ffffffb3;
+}
+
+.option:hover {
+ background-color: rgb(0, 0, 0);
+ color: #ffffff;
+ transform: translateX(5px);
+}
+
+.options input[type="radio"] {
+ display: none;
+}
+
+.options label {
+ display: inline-block;
+ cursor: pointer;
+ text-decoration: none;
+ color: inherit;
+ width: 100%;
+}
+
+.options label::before {
+ content: attr(data-txt);
+ cursor: pointer;
+ text-decoration: none;
+}
+
+.options input[type="radio"]:checked + label {
+ display: none;
+}
+
+.options input[type="radio"]#all:checked + label {
+ display: none;
+}
+
+a {
+ cursor: pointer;
+ text-decoration: none;
+ color: inherit;
+}
+
+.mobileMenuToggle {
+ display: none;
+ background: none;
+ border: none;
+ cursor: pointer;
+ padding: 0.5rem;
+ z-index: 1003;
+}
+
+.mobileMenuIcon {
+ width: 2rem;
+ height: 2rem;
+ fill: #ffffff;
+}
+
+
+@media (min-width: 1440px) {
+
+ .logo {
+ font-size: 2rem;
+ }
+
+ .menuimg {
+ width: 4rem;
+ }
+
+ .selected {
+ padding: 1rem 1.25rem;
+ font-size: 1rem;
+ }
+
+ .options {
+ min-width: 14rem;
+ }
+
+ .option {
+ padding: 1rem 1.25rem;
+ font-size: 1rem;
+ }
+}
+
+@media (max-width: 1199px) {
+
+ .logo {
+ font-size: 1.25rem;
+ }
+
+ .menuimg {
+ width: 3.5rem;
+ }
+
+ .selected {
+ padding: 0.625rem 0.875rem;
+ }
+
+ .options {
+ min-width: 11rem;
+ }
+}
+
+@media (max-width: 1023px) {
+
+ .logo {
+ font-size: 1.1rem;
+ }
+
+ .menuimg {
+ width: 3rem;
+ }
+
+ .select {
+ margin-left: 0;
+ }
+
+ .selected {
+ padding: 0.5rem 0.75rem;
+ min-width: 3rem;
+ min-height: 3rem;
+ }
+
+ .arrow {
+ display: none;
+ }
+
+ .options {
+ right: -50%;
+ transform: translateX(-50%) translateY(-10px);
+ }
+
+ .select:hover .options,
+ .select:focus-within .options {
+ transform: translateX(-50%) translateY(0);
+ }
+}
+
+@media (max-width: 767px) {
+
+ .logo {
+ font-size: 1rem;
+ }
+
+ .menuimg {
+ width: 2.5rem;
+ }
+
+ .selected {
+ padding: 0.4rem 0.6rem;
+ font-size: 0.8rem;
+ min-width: 2.5rem;
+ min-height: 2.5rem;
+ }
+
+ .options {
+ min-width: 10rem;
+ right: -70%;
+ }
+
+ .option {
+ padding: 0.625rem 0.75rem;
+ font-size: 0.85rem;
+ }
+
+ .mobileMenuToggle {
+ display: block;
+ }
+
+ .select {
+ position: fixed;
+ top: 1rem;
+ right: 1rem;
+ }
+
+ .options {
+ position: fixed;
+ top: 4rem;
+ right: 1rem;
+ left: 1rem;
+ min-width: auto;
+ max-width: 300px;
+ margin: 0 auto;
+ }
+}
+
+@media (max-width: 575px) {
+
+ .logo {
+ font-size: 0.9rem;
+ }
+
+ .menuimg {
+ width: 2rem;
+ }
+
+ .selected {
+ padding: 0.3rem 0.5rem;
+ min-width: 2rem;
+ min-height: 2rem;
+ }
+
+ .selected span {
+ display: none;
+ }
+
+ .options {
+ position: fixed;
+ top: 3.5rem;
+ right: 0.5rem;
+ left: 0.5rem;
+ max-width: 250px;
+ }
+
+ .option {
+ padding: 0.5rem 0.625rem;
+ font-size: 0.8rem;
+ }
+}
+
+@media (max-width: 320px) {
+
+ .logo {
+ font-size: 0.8rem;
+ }
+
+ .menuimg {
+ width: 1.75rem;
+ }
+
+ .selected {
+ padding: 0.25rem 0.4rem;
+ min-width: 1.75rem;
+ min-height: 1.75rem;
+ }
+
+ .options {
+ top: 3rem;
+ right: 0.25rem;
+ left: 0.25rem;
+ max-width: 200px;
+ }
+
+ .option {
+ padding: 0.4rem 0.5rem;
+ font-size: 0.75rem;
+ }
+}
+
+@media (max-height: 600px) and (orientation: portrait) {
+ .options {
+ max-height: 300px;
+ overflow-y: auto;
+ }
+}
+
+@media (min-width: 768px) and (max-width: 1023px) and (orientation: landscape) {
+ .options {
+ right: 0;
+ transform: translateY(-10px);
+ }
+
+ .select:hover .options,
+ .select:focus-within .options {
+ transform: translateY(0);
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ .selected {
+ background-color: rgba(20, 20, 20, 0.9);
+ }
+
+ .options {
+ background-color: rgba(20, 20, 20, 0.95);
+ }
+
+ .option:hover {
+ background-color: rgba(40, 45, 55, 0.5);
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.options {
+ animation: fadeIn 0.3s ease forwards;
+}
+
+.selected:focus,
+.option:focus {
+ outline: 2px solid #667eea;
+ outline-offset: 2px;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .menuimg,
+ .selected,
+ .options,
+ .option,
+ .arrow {
+ transition: none;
+ }
+
+ .options {
+ animation: none;
+ }
+}
+
+@supports (-webkit-touch-callout: none) {
+ .selected {
+ -webkit-tap-highlight-color: transparent;
+ }
+
+ .option {
+ -webkit-tap-highlight-color: rgba(255, 255, 255, 0.1);
+ }
+}
+
+.loadingMenu {
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 0.9rem;
+ color: rgba(255, 255, 255, 0.7);
+ padding: 1rem;
+ text-align: center;
+}
+
+.authStatus {
+ font-size: 0.8rem;
+ margin-left: 0.5rem;
+ opacity: 0.7;
+}
+
+.menuItemWrapper {
+ width: 100%;
+}
+
+.menuLink {
+ display: block;
+ width: 100%;
+ text-decoration: none;
+ color: inherit;
+ cursor: pointer;
+}
+
+.menuLink:hover {
+ background-color: inherit;
+}
@@ -0,0 +1,14 @@
+import styles from './MainButton.module.css'
+import { Link } from 'react-router-dom';
+import { Icon } from './icon.js';
+
+export default function MainButton() {
+ return (
+
+
+ Больше моделей
+
+
+
+ );
+}
@@ -0,0 +1,67 @@
+
+.cssbuttonsIoButton {
+ font-family: "Orbitron", sans-serif;
+ background: #ebebeb;
+ color: rgb(0, 0, 0);
+ padding: 0.35em;
+ padding-left: 3.5rem;
+ font-size: 17px;
+ font-weight: 600;
+ border-radius: 0.25rem;
+ border: none;
+ letter-spacing: 0.05em;
+ display: flex;
+ align-items: center;
+ box-shadow: inset 0 0 1.6em -0.6em #ffffff;
+ overflow: hidden;
+ position: relative;
+ height: 2.8em;
+ padding-right: 8rem;
+ cursor: pointer;
+}
+
+ .icon{
+ background: #a2b8d9;
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 2.5em;
+ width: 2.5em;
+ border-radius: 0.25rem;
+ box-shadow: 0.1em 0.1em 0.6em 0.1em #ffffff;
+ right: 0.3em;
+ transition: all 0.3s;
+}
+
+
+.cssbuttonsIoButton:hover .icon {
+ width: calc(100% - 0.6em);
+}
+
+.cssbuttonsIoButton .icon svg {
+ width: 1.1em;
+ transition: transform 0.3s;
+ color: #ffffff;
+}
+
+.cssbuttonsIoButton:hover .icon svg {
+ transform: translateX(0.1em);
+}
+
+.cssbuttonsIoButton:active .icon {
+ transform: scale(0.95);
+}
+a {
+ cursor: pointer;
+ text-decoration: none;
+}
+
+a:visited {
+ color: inherit;
+}
+.a {
+ position: absolute;
+ margin-top: 15rem;
+ margin-left: 8.0625rem;
+}
@@ -0,0 +1,23 @@
+import React from 'react';
+import styles from './MainButton.module.css'
+
+
+export const Icon = ({
+}) => {
+ return (
+
+ );
+};
@@ -0,0 +1,50 @@
+import { useState } from "react";
+import styles from './Slider.module.css'
+import { slides } from '../constants';
+
+export default function FunctionSlide() {
+
+ const [currentSlide, setCurrentSlide] = useState(0);
+
+ const nextSlide = () => {
+ setCurrentSlide((prev) => (prev === slides.length - 1 ? 0 : prev + 1));
+ };
+
+ const prevSlide = () => {
+ setCurrentSlide((prev) => (prev === 0 ? slides.length - 1 : prev - 1));
+ };
+
+ if (!slides || slides.length === 0) {
+ return Нет слайдов для отображения
;
+ }
+
+ return (
+
+
+
+ ❮
+
+
+ ❯
+
+
+
+
+
+
+
{slides[currentSlide].nameSlide}
+ {slides[currentSlide].text}
+
+
+
+ {slides[currentSlide].calibr}
+ {slides[currentSlide].diametr}
+
+
+
+ );
+}
@@ -0,0 +1,103 @@
+.container {
+ display: flex;
+ transition: transform 0.5s ease-in-out;
+ width: 2rem;
+}
+
+.prevbtn,
+.nextbtn {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ background: rgba(255, 255, 255, 0.5);
+ border-radius: 100px;
+ color: white;
+ border: none;
+ padding: 8px 16px 8px 16px;
+ cursor: pointer;
+ font-size: 18px;
+ font-weight: bold;
+ z-index: 2;
+}
+
+.prevbtn {
+ margin-left: 58.7rem;
+}
+
+.nextbtn {
+ margin-left: 90rem;
+}
+
+.slide {
+ transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out;
+}
+
+.slideContent {
+ text-align: justify;
+ color: #ffffff;
+ margin-left: 8rem;
+}
+h1 {
+ margin-top: 15rem;
+ font-family: "Orbitron", sans-serif;
+ font-size: 9.875rem;
+ padding-bottom: 3rem;
+}
+.slideText {
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 1.125rem;
+ color: #ffffff;
+ position: absolute;
+ margin-left: 102rem;
+ gap: 1rem;
+ flex-direction: column;
+ display: flex;
+ margin-top: 15rem;
+ width: 13rem;
+ word-spacing: 5rem;
+}
+
+.description {
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 1.125rem;
+ width: 100%;
+}
+.slideImage {
+ position: absolute;
+ padding-left: 63rem;
+ display: flex;
+ padding-top: 12rem;
+ animation: 0.5s ease-in-out forwards;
+ width: 74%;
+}
+
+.slide.next {
+ animation: slideInNext 0.5s ease-in-out forwards;
+}
+
+.slide.prev {
+ animation: slideInPrev 0.5s ease-in-out forwards;
+}
+
+@keyframes slideInNext {
+ 0% {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+@keyframes slideInPrev {
+ 0% {
+ transform: translateX(-100%);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
@@ -0,0 +1,32 @@
+import styles from './Cards.module.css'
+import { useState } from 'react';
+import { useCart } from '../../hooks/UseCart.js';
+
+export const Card = ({ id, title, description, photo, price }) => {
+ const { addToCart } = useCart();
+ const [isAdding, setIsAdding] = useState(false);
+ const handleAddToCart = () => {
+ setIsAdding(true);
+ addToCart({ id, title, description, photo, price });
+ setTimeout(() => {
+ setIsAdding(false);
+ }, 300);
+ };
+ return (
+
+
{title}
+
+
{description}
+
+ {price}$
+
+ {isAdding ? 'Добавлено!' : 'В корзину'}
+
+
+
+ );
+};
\ No newline at end of file
@@ -0,0 +1,40 @@
+import styles from './Cards.module.css'
+import { cardsData } from '../constants.js'
+import { Card } from './Card.jsx';
+
+export default function CardsGrid(){
+ const chunkArray = (array, chunkSize) => {
+ const result = [];
+ for (let i = 0; i < array.length; i += chunkSize) {
+ result.push(array.slice(i, i + chunkSize));
+ }
+ return result;
+ };
+
+ const cardGroups = chunkArray(cardsData, 3);
+ const backgroundStyle = {
+ backgroundImage: `url(${process.env.PUBLIC_URL}/images/fon.svg)`,
+ backgroundSize: 'cover',
+ backgroundPosition: 'center',
+ backgroundRepeat: 'no-repeat'
+ };
+ return (
+
+ {cardGroups.map((group, groupIndex) => (
+
+ {group.map((card) => (
+
+ ))}
+
+ ))}
+
+ );
+};
+
+
@@ -0,0 +1,82 @@
+
+.container {
+ margin-left: 3rem;
+ margin-right: 3rem;
+ padding: 10px;
+ padding-top: 10rem;
+
+}
+.image{
+ width: 17rem;
+ height: auto;
+ padding-top: 2.3rem;
+ margin-bottom: 2.625rem;
+ max-height: 34rem;
+
+}
+.row {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 4rem;
+ margin-bottom: 10rem;
+ text-align: center;
+}
+.card {
+ text-align: center;
+ border-radius: 8px;
+ padding: 20px;
+ transition: transform 0.3s ease;
+}
+
+.card:hover {
+ transform: translateY(-5px);
+
+}
+
+.title {
+ font-family: "Orbitron", sans-serif;
+ font-size: 3rem;
+ margin-bottom: 10px;
+ color: #000000;
+ text-align: center;
+
+}
+
+.description {
+ margin-left: 6.5rem;
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 1.125rem;
+ line-height: 1.5;
+ color: #000000;
+ margin-bottom: 15px;
+ display: flex;
+ text-align: justify;
+ width: 20rem;
+}
+
+.footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.counter {
+ font-family: "Orbitron", sans-serif;
+ font-size: 1.5rem;
+ margin-left: 3.5625rem;
+ padding-top: 0.623rem;
+ font-weight: bold;
+ color: #000000;
+}
+.addToCartButton{
+ display: flex;
+ width: 11.625rem;
+ background-color: #000000;
+ height: 2.875rem;
+ display: flex;
+ font-family: "Didact Gothic", sans-serif;
+ font-size: 1.25rem;
+ color: #ffffff;
+ padding-left: 3rem;
+ padding-top: 0.623rem;
+}
@@ -0,0 +1,46 @@
+import { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+
+export default function Loader() {
+
+
+const navigate = useNavigate();
+ const [user, setUser] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+
+
+
+ useEffect(() => {
+ const loadUserData = () => {
+ setIsLoading(true);
+ try {
+ const savedUser = localStorage.getItem('currentUser');
+ if (savedUser) {
+ const userData = JSON.parse(savedUser);
+ setUser(userData);
+
+ } else {
+ navigate('/login');
+ }
+ } catch (error) {
+ console.error('Ошибка загрузки данных пользователя:', error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+ loadUserData();
+ }, [navigate]);
+ if (isLoading) {
+ return (
+
+
+
Загрузка профиля...
+
+ );
+ }
+
+ if (!user) {
+ return null;
+ }
+}
\ No newline at end of file
@@ -0,0 +1,136 @@
+
+export const guestNavItems = [
+ { id: 'home', title: 'Главная страница', path: '/', label: 'Главная' },
+ { id: 'catalog', title: 'Каталог товаров', path: '/catalog', label: 'Каталог' },
+ { id: 'about', title: 'О нашей компании', path: '/about', label: 'О нас' },
+ { id: 'login', title: 'Вход в систему', path: '/login', label: 'Войти' },
+ ];
+
+export const authNavItems = [
+
+ { id: 'home', title: 'Главная страница', path: '/', label: 'Главная' },
+ { id: 'catalog', title: 'Каталог товаров', path: '/catalog', label: 'Каталог' },
+ { id: 'about', title: 'О нашей компании', path: '/about', label: 'О нас' },
+ { id: 'profile', title: 'Личный кабинет', path: '/profile', label: 'Профиль' },
+ { id: 'basket', title: 'Корзина покупок', path: '/basket', label: 'Корзина' },
+ ];
+
+export const footer = [
+ {
+ id: "section-1",
+ className: "link",
+ links: [
+ { id: 1, path: "/404", title: "О нас" },
+ { id: 2, path: "/404", title: "Политика обработки персональных данных" },
+ { id: 3, path: "/404", title: "Документы на веб-сайте" },
+ { id: 4, path: "", title: "` " },
+ { id: 5, path: "", title: "` " },
+ { id: 6, path: "/404", title: "Вопросы и ответы" },
+ { id: 7, path: "/404", title: "Заказы и доставка" },
+ { id: 8, path: "/404", title: "Возврат товара" }
+ ]
+ },
+ {
+ id: "section-2",
+ className: "linkSocial",
+ links: [
+ { id: 9, path: "404", title: "INSTAGRAM", external: true },
+ { id: 10, path: "404", title: "VK", external: true },
+ { id: 11, path: "404", title: "YOUTUBE", external: true },
+ { id: 12, path: "404", title: "TELEGRAM", external: true }
+ ]
+ }
+];
+
+export const slides = [
+ {
+ id: 1,
+ img: "/images/rolex.svg",
+ nameSlide: "ROLEX",
+ text: "Коллекция Rolex представлена престижными и высокоточными часовыми моделями на любой вкус, от Профессиональных до Классических.",
+ calibr: "калибр 7135",
+ diametr: "диаметр 40мм",
+ },
+ {
+ id: 2,
+ img: "/images/longines.svg",
+ nameSlide: "Longines",
+ text: "Коллекция Longines представлена престижными и высокоточными часовыми моделями на любой вкус, от Профессиональных до Классических.",
+ calibr: "калибр 8175",
+ diametr: "диаметр 36мм",
+ },
+ {
+ id: 3,
+ img: "/images/marvin.svg",
+ nameSlide: "MARVIN",
+ text: "Коллекция MARVIN представлена престижными и высокоточными часовыми моделями на любой вкус, от Профессиональных до Классических.",
+ calibr: "калибр 3671",
+ diametr: "диаметр 36мм",
+ },
+ ];
+
+export const cardsData = [
+ {
+ id: 1,
+ title: "ROLEX",
+ photo:'/images/rolex.svg',
+ description: "Ролекс - роскошные часы с классическим дизайном, прочными корпусами и высокоточными механизмами.",
+ price: 10000,
+ },
+ {
+ id: 2,
+ title: "LONGINES",
+ photo:'/images/longines.svg',
+ description: "Longines - швейцарские часы с длинной истории и традициями. Известны своей элегантностью, точностью и качеством.",
+ price: 12000,
+ },
+ {
+ id: 3,
+ title: "MARVIN",
+ photo:'/images/marvin.svg',
+ description: "MARVIN известен своими точными механическими часами, которые пользуются популярностью.",
+ price: 19000,
+ },
+ {
+ id: 4,
+ title: "ZENITH",
+ photo:'/images/zenith.svg',
+ description: "Зенит известна своей инновационной технологией и высокой точностью. Одним из самых известных моделей Зенита является Эль-Примо.",
+ price: 11000,
+ },
+ {
+ id: 5,
+ title: "PAUL HEITT",
+ photo:'/images/paul.svg',
+ description: "Пол Хевитт известен своими стильными и функциональными часами, которые сочетают в себе современный дизайн и высокую точность.",
+ price: 22000,
+ },
+ {
+ id: 6,
+ title: "LONGINES",
+ photo:'/images/longines2.svg',
+ description: "Longines - швейцарские часы с длинной истории и традициями. Известны своей элегантностью, точностью и качеством.",
+ price: 10000,
+ },
+ {
+ id: 7,
+ title: "Hampden",
+ photo:'/images/hampden.svg',
+ description: "Хэмпден известен своими высокоточными часами и механизмами, которые производятся вручную в Шотландии",
+ price: 11000,
+ },
+ {
+ id: 8,
+ title: "ROLEX",
+ photo:'/images/rolex2.svg',
+ description: "Ролекс - роскошные часы с классическим дизайном, прочными корпусами и высокоточными механизмами.",
+ price: 22000,
+ },
+ {
+ id: 9,
+ title: "OMEGA",
+ photo:'/images/omega.svg',
+ description: "Omega - это швейцарская марка часов, известная своей высокой точностью, инновациями и историческими достижениями.",
+ price: 12000,
+ },
+];
@@ -0,0 +1,73 @@
+import { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+export function useAuth(redirectToLogin = true) {
+ const navigate = useNavigate();
+ const [user, setUser] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
+
+ useEffect(() => {
+ const loadUserData = () => {
+ setIsLoading(true);
+ try {
+ const savedUser = localStorage.getItem('currentUser');
+ if (savedUser) {
+ const userData = JSON.parse(savedUser);
+ setUser(userData);
+ setIsAuthenticated(true);
+ } else {
+ setUser(null);
+ setIsAuthenticated(false);
+ if (redirectToLogin) {
+ navigate('/login');
+ }
+ }
+ } catch (error) {
+ console.error('Ошибка загрузки данных пользователя:', error);
+ setUser(null);
+ setIsAuthenticated(false);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ loadUserData();
+
+ const handleStorageChange = (e) => {
+ if (e.key === 'currentUser') {
+ loadUserData();
+ }
+ };
+
+ window.addEventListener('storage', handleStorageChange);
+
+ return () => {
+ window.removeEventListener('storage', handleStorageChange);
+ };
+ }, [navigate, redirectToLogin]);
+
+ const logout = () => {
+ localStorage.removeItem('currentUser');
+ setUser(null);
+ setIsAuthenticated(false);
+ if (redirectToLogin) {
+ navigate('/login');
+ }
+ };
+
+ const login = (userData) => {
+ localStorage.setItem('currentUser', JSON.stringify(userData));
+ setUser(userData);
+ setIsAuthenticated(true);
+ };
+
+ return {
+ user,
+ isLoading,
+ isAuthenticated,
+ login,
+ logout,
+ setUser
+ };
+}
\ No newline at end of file
@@ -0,0 +1,70 @@
+import { useState, useEffect } from 'react';
+
+export const useCart = () => {
+ const [cart, setCart] = useState(() => {
+ try {
+ const savedCart = localStorage.getItem('cart');
+ return savedCart ? JSON.parse(savedCart) : [];
+ } catch (error) {
+ return [];
+ }
+ });
+
+ useEffect(() => {
+ localStorage.setItem('cart', JSON.stringify(cart));
+ }, [cart]);
+
+ const addToCart = (product) => {
+ if (!product || !product.id) {
+ return;
+ }
+
+ setCart(prevCart => {
+ const existingItem = prevCart.find(item => item.id === product.id);
+
+ if (existingItem) {
+ return prevCart.map(item =>
+ item.id === product.id
+ ? { ...item, quantity: item.quantity + 1 }
+ : item
+ );
+ } else {
+ return [...prevCart, {
+ id: product.id,
+ title: product.title || product.name || 'Без названия',
+ description: product.description || '',
+ price: Number(product.price) || 0,
+ photo: product.photo || product.image || '',
+ quantity: 1
+ }];
+ }
+ });
+ };
+
+ const removeFromCart = (productId) => {
+ setCart(prevCart => prevCart.filter(item => item.id !== productId));
+ };
+
+
+
+ const clearCart = () => {
+ setCart([]);
+ };
+
+ const calculateTotal = () => {
+ return cart.reduce((total, item) => total + (item.price * item.quantity), 0);
+ };
+
+ const calculateItemsCount = () => {
+ return cart.reduce((total, item) => total + item.quantity, 0);
+ };
+
+ return {
+ cart,
+ addToCart,
+ removeFromCart,
+ clearCart,
+ calculateTotal,
+ calculateItemsCount
+ };
+};
\ No newline at end of file
@@ -0,0 +1,56 @@
+import Footer from "../../components/Footer/Footer";
+import styles from './About.module.css'
+
+export default function Catalog(){
+ return(
+ <>
+
+
+
+ prime
+ Prime — время стильных решений, которые подчеркивают вашу
+ индивидуальность и надежность.
+ Создаем будущее вместе с вами, воплощая инновации и качество в каждом
+ шаге.
+
+
+
+
+
+
+
+ Компания Prime — это ведущий онлайн-ритейлер в сфере продажи часов,
+ ставший выбором номер один для ценителей точности, стиля и надежности.
+ Мы предлагаем широкий ассортимент часов от мировых брендов, таких как
+ Rolex, Omega, Casio, Seiko и многие другие, чтобы удовлетворить любые
+ предпочтения и бюджеты. В Prime каждый клиент найдет идеальную модель
+ — будь то элегантные классические часы для деловых встреч, спортивные
+ модели для активного образа жизни или современные стильные аксессуары
+ для повседневного использования.
+
+ Наши преимущества:
+
+ - Официальная гарантия на все товары
+ - Гарантированная оригинальность продукции
+ - Консультации специалистов для выбора идеальной модели
+ - Быстрая и надежная доставка по всей стране и за рубеж
+ - Удобные способы оплаты и возврата
+
+
+
+ Мы ценим каждого клиента и стремимся сделать покупку максимально
+ комфортной и приятной. В Prime вас ждут не только качественные часы,
+ но и высокий уровень сервиса, индивидуальный подход и постоянное
+ обновление ассортимента. Независимо от того, ищете ли вы классический
+ аксессуар, современный дизайн или уникальную модель — в Prime вы
+ обязательно найдете то, что подчеркнет вашу индивидуальность и стиль.
+
+
+
+
+
+
+
+ >)
+}
\ No newline at end of file
@@ -0,0 +1,72 @@
+
+.body{
+ background-color: black;
+ display: grid;
+ justify-content: center;
+}
+video{
+ width: 98rem;
+ margin-top: 10rem;
+
+}
+.img{
+ width: 98rem;
+}
+main {
+ 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;
+
+}
+img {
+ width: 103.875rem;
+ height: auto;
+}
+.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;
+}
@@ -0,0 +1,152 @@
+import { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import styles from "./Login.module.css";
+
+export default function Login() {
+ const navigate = useNavigate();
+ const [formData, setFormData] = useState({
+ email: '',
+ password: ''
+ });
+
+ const [fieldErrors, setFieldErrors] = useState({});
+ const [isLoading, setIsLoading] = useState(false);
+ const [serverError, setServerError] = useState('');
+ const [showErrors, setShowErrors] = useState(false);
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({
+ ...prev,
+ [name]: value
+ }));
+
+ if (fieldErrors[name]) {
+ setFieldErrors(prev => ({
+ ...prev,
+ [name]: ''
+ }));
+ }
+
+ if (serverError) {
+ setServerError('');
+ }
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setShowErrors(true);
+ setServerError('');
+
+ const newErrors = {};
+
+ if (!formData.email.trim()) newErrors.email = 'Заполните это поле.';
+ if (!formData.password) newErrors.password = 'Заполните это поле.';
+
+ if (Object.keys(newErrors).length > 0) {
+ setFieldErrors(newErrors);
+ return;
+ }
+
+ setIsLoading(true);
+
+ try {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+
+ const users = JSON.parse(localStorage.getItem('registeredUsers') || '[]');
+ const user = users.find(u => u.email === formData.email);
+
+ if (!user) {
+ setServerError('Пользователь с таким email не найден');
+ 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) {
+ console.error('Ошибка при входе:', error);
+ setServerError('Ошибка сервера. Попробуйте позже.');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const getInputClass = (fieldName) => {
+ if (showErrors && fieldErrors[fieldName]) {
+ return `${styles.input} ${styles.inputError}`;
+ }
+ return styles.input;
+ };
+
+ const getPlaceholder = (fieldName, defaultPlaceholder) => {
+ if (showErrors && fieldErrors[fieldName]) {
+ return fieldErrors[fieldName];
+ }
+ return defaultPlaceholder;
+ };
+
+ return (
+
+
Вход
+
+
+
+
+
+
+
+ );
+}
@@ -0,0 +1,88 @@
+
+.body{
+ background-color: black;
+ padding-bottom: 9.5rem;
+}
+.fon {
+ width: 78.375rem;
+ height: auto;
+ padding-top: 13.125rem;
+ margin-left: 21.5rem;
+}
+.h1 {
+ font-family: "Orbitron", sans-serif;
+ font-size: 4rem;
+ color: #ffffff;
+ font-weight: 700;
+ margin-top: 15.1875rem;
+ margin-left: 53rem;
+ position: absolute;
+}
+.group{
+ position: absolute;
+ display: grid;
+ margin-left: 39.125rem;
+ margin-top: 30rem;
+ gap: 1rem;
+}
+.input {
+ width: 41.75rem;
+ 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: 1.1rem;
+ color: #ffffff;
+
+}
+.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: 24.0625rem;
+ height: 3.75rem;
+ background-color: #ffffff;
+ border-radius: 0.625rem;
+ margin-top: 43.25rem;
+ margin-left: 47.9375rem;
+}
+.buttontext{
+ font-family: "Orbitron", sans-serif;
+ font-size: 1.25rem;
+ text-align: center;
+
+ display: block;
+}
+
+.button:hover{
+transform: scale(1.1);
+cursor: pointer;
+}
+.text{
+
+ font-family: "Orbitron", sans-serif;
+ font-size: 1rem;
+ color: #ffffff;
+ text-align: center;
+}
+.link{
+ font-family: "Orbitron", sans-serif;
+ font-size: 1rem;
+ color: #120fa0;
+}
@@ -0,0 +1,181 @@
+import { useState } from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+import styles from "./Registration.module.css";
+
+export default function Registration() {
+ const navigate = useNavigate();
+
+ const [formData, setFormData] = useState({
+ email: '',
+ fullName: '',
+ phone: '',
+ password: '',
+ confirmPassword: ''
+ });
+
+ const [fieldErrors, setFieldErrors] = useState({});
+ const [isLoading, setIsLoading] = useState(false);
+ const [showErrors, setShowErrors] = useState(false);
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({
+ ...prev,
+ [name]: value
+ }));
+
+ if (fieldErrors[name]) {
+ setFieldErrors(prev => ({
+ ...prev,
+ [name]: ''
+ }));
+ }
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setShowErrors(true);
+
+ const newErrors = {};
+
+ if (!formData.email.trim()) newErrors.email = 'Заполните это поле.';
+ if (!formData.fullName.trim()) newErrors.fullName = 'Заполните это поле.';
+ if (!formData.phone.trim()) newErrors.phone = 'Заполните это поле.';
+ if (!formData.password) newErrors.password = 'Заполните это поле.';
+ if (!formData.confirmPassword) newErrors.confirmPassword = 'Заполните это поле.';
+
+ if (Object.keys(newErrors).length > 0) {
+ setFieldErrors(newErrors);
+ return;
+ }
+
+ setIsLoading(true);
+
+ try {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ console.log('Данные для регистрации:', formData);
+
+ const userData = {
+ email: formData.email,
+ fullName: formData.fullName,
+ phone: formData.phone,
+ registeredAt: new Date().toISOString(),
+ };
+
+ localStorage.setItem('currentUser', JSON.stringify(userData));
+
+ const existingUsers = JSON.parse(localStorage.getItem('registeredUsers') || '[]');
+ localStorage.setItem('registeredUsers', JSON.stringify([...existingUsers, userData]));
+
+ console.log('Пользователь зарегистрирован:', userData);
+
+
+ setTimeout(() => {
+ navigate('/login');
+ }, 2000);
+
+ } catch (error) {
+ console.error('Ошибка регистрации:', error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+ const getInputClass = (fieldName) => {
+ if (showErrors && fieldErrors[fieldName]) {
+ return `${styles.input} ${styles.inputError}`;
+ }
+ return styles.input;
+ };
+
+ const getPlaceholder = (fieldName, defaultPlaceholder) => {
+ if (showErrors && fieldErrors[fieldName]) {
+ return fieldErrors[fieldName];
+ }
+ return defaultPlaceholder;
+ };
+
+ return (
+
+
Регистрация
+
+
+
+
+
+ );
+}
\ No newline at end of file
@@ -0,0 +1,88 @@
+
+.body{
+ background-color: black;
+ padding-bottom: 9.5rem;
+}
+.fon {
+ width: 78.375rem;
+ height: auto;
+ padding-top: 13.125rem;
+ margin-left: 21.5rem;
+}
+.h1 {
+ font-family: "Orbitron", sans-serif;
+ font-size: 4rem;
+ color: #ffffff;
+ font-weight: 700;
+ margin-top: 15.1875rem;
+ margin-left: 48rem;
+ position: absolute;
+}
+.group{
+ position: absolute;
+ display: grid;
+ margin-left: 39.125rem;
+ margin-top: 25rem;
+ gap: 1rem;
+}
+.input {
+ width: 41.75rem;
+ 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: 1.1rem;
+ color: #ffffff;
+
+}
+.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: 24.0625rem;
+ height: 3.75rem;
+ background-color: #ffffff;
+ border-radius: 0.625rem;
+ margin-top: 51rem;
+ margin-left: 47.9375rem;
+}
+.buttontext{
+ font-family: "Orbitron", sans-serif;
+ font-size: 1.25rem;
+ text-align: center;
+
+ display: block;
+}
+
+.button:hover{
+transform: scale(1.1);
+cursor: pointer;
+}
+.text{
+
+ font-family: "Orbitron", sans-serif;
+ font-size: 1rem;
+ color: #ffffff;
+ text-align: center;
+}
+.link{
+ font-family: "Orbitron", sans-serif;
+ font-size: 1rem;
+ color: #120fa0;
+}
@@ -0,0 +1,11 @@
+import Footer from "../../components/Footer/Footer";
+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,9 @@
+import Footer from "../../components/Footer/Footer";
+import CardsGrid from "../../components/Сards/Cards";
+
+export default function Catalog(){
+ return(
+
+
+
)
+}
\ No newline at end of file
@@ -0,0 +1,13 @@
+import styles from "./Error.module.css"
+
+
+ export default function Error(){
+ return (
+
+
+
404
+ Страница не найдена
+
+
+ );
+ }
\ No newline at end of file
@@ -0,0 +1,19 @@
+
+.body{
+ 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,12 @@
+import styles from './Home.module.css'
+import MainButton from "../../components/MainButton/MainButton";
+import FunctionSlide from "../../components/Slider/Slide";
+
+ export default function Home(){
+ return (
+
+
+
+
+ );
+ }
\ No newline at end of file
@@ -0,0 +1,9 @@
+
+.body {
+ font-size: 16px;
+ width: 100%;
+ height: 65rem;
+ background-size: 119rem;
+ background-image: url(/public/images/homeFon.svg);
+
+}
@@ -0,0 +1,9 @@
+import Footer from "../../components/Footer/Footer";
+import DataProfile from "../../components/DataProfile/DataProfile"
+
+export default function Profile(){
+ return(
+
+
+
)
+}
\ No newline at end of file
@@ -0,0 +1,49 @@
+@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,34 @@
+ 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";
+
+function App() {
+ return (
+ <>
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+ >
+ );
+}
+
+export default App;
@@ -0,0 +1,8 @@
+import { render, screen } from '@testing-library/react';
+import App from './App';
+
+test('renders learn react link', () => {
+ render( );
+ const linkElement = screen.getByText(/learn react/i);
+ expect(linkElement).toBeInTheDocument();
+});
@@ -0,0 +1,51 @@
+main{
+ color: black;
+}
+@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;
+}
+.body{
+ background-color: black;
+
+}
+@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,12 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render(
+
+
+
+);
+
@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
@@ -0,0 +1,35 @@
+{
+ "name": "my-app",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "react": "^19.2.3",
+ "react-dom": "^19.2.3",
+ "react-hot-toast": "^2.6.0",
+ "react-router-dom": "^7.11.0"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}