Kgshop commited on
Commit
207f40f
·
verified ·
1 Parent(s): ece89ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -153
app.py CHANGED
@@ -13,7 +13,7 @@ app = Flask(__name__)
13
  DATA_FILE = 'data_kanc.json'
14
 
15
  # Настройки Hugging Face
16
- REPO_ID = "Kgshop/clients"
17
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
18
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
19
 
@@ -27,7 +27,7 @@ def load_data():
27
  data = json.load(file)
28
  logging.info("Данные успешно загружены из JSON")
29
  if not isinstance(data, dict) or 'products' not in data or 'categories' not in data:
30
- return {'products': [], 'categories': [] if not isinstance(data, list) else data}
31
  return data
32
  except FileNotFoundError:
33
  logging.warning("Локальный файл базы данных не найден после скачивания.")
@@ -94,8 +94,8 @@ def periodic_backup():
94
  def catalog():
95
  data = load_data()
96
  products = data['products']
97
- categories = data['categories']
98
-
99
  catalog_html = '''
100
  <!DOCTYPE html>
101
  <html lang="ru">
@@ -107,6 +107,7 @@ def catalog():
107
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
108
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
109
  <style>
 
110
  * {
111
  margin: 0;
112
  padding: 0;
@@ -158,13 +159,7 @@ def catalog():
158
  body.dark-mode .theme-toggle {
159
  color: #bbb;
160
  }
161
- .filters-container {
162
- margin: 20px 0;
163
- display: flex;
164
- flex-wrap: wrap;
165
- gap: 10px;
166
- justify-content: center;
167
- }
168
  .search-container {
169
  margin: 20px 0;
170
  text-align: center;
@@ -184,33 +179,13 @@ def catalog():
184
  border-color: #526df2;
185
  box-shadow: 0 4px 15px rgba(82, 109, 242, 0.2);
186
  }
187
- .category-filter {
188
- padding: 10px 20px;
189
- border: 1px solid rgba(0, 0, 0, 0.1);
190
- border-radius: 25px;
191
- background-color: #fff;
192
- cursor: pointer;
193
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
194
- font-size: 0.9rem;
195
- font-weight: 500;
196
- }
197
- .category-filter.active, .category-filter:hover {
198
- background-color: #526df2;
199
- color: white;
200
- border-color: #526df2;
201
- box-shadow: 0 2px 10px rgba(82, 109, 242, 0.3);
202
- }
203
- body.dark-mode .category-filter {
204
- background-color: #2a2a3e;
205
- border-color: rgba(255, 255, 255, 0.1);
206
- color: #e0e0e0;
207
- }
208
  .products-grid {
209
  display: grid;
210
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
211
  gap: 20px;
212
  padding: 10px;
213
  }
 
214
  .product {
215
  background: rgba(255, 255, 255, 0.8);
216
  border: 1px solid rgba(0, 0, 0, 0.05);
@@ -509,6 +484,32 @@ def catalog():
509
  font-size: 0.75rem;
510
  font-weight: 500;
511
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  </style>
513
  </head>
514
  <body>
@@ -519,12 +520,15 @@ def catalog():
519
  <i class="fas fa-moon"></i>
520
  </button>
521
  </div>
522
- <div class="filters-container">
523
- <button class="category-filter active" data-category="all">Все категории</button>
524
- {% for category in categories %}
525
- <button class="category-filter" data-category="{{ category }}">{{ category }}</button>
526
- {% endfor %}
 
 
527
  </div>
 
528
  <div class="search-container">
529
  <input type="text" id="search-input" placeholder="Поиск товаров...">
530
  </div>
@@ -604,15 +608,6 @@ def catalog():
604
  </div>
605
  </div>
606
 
607
- <!-- Address Modal -->
608
- <div id="addressModal" class="modal">
609
- <div class="modal-content">
610
- <span class="close" onclick="closeModal('addressModal')">×</span>
611
- <h2>Наш адрес</h2>
612
- <p>Рынок Дордой, Джунхай, 5 проход 505-506 контейнеры</p>
613
- </div>
614
- </div>
615
-
616
  <button id="cart-button" onclick="openCartModal()">🛒</button>
617
 
618
  <!-- Navigation Bar -->
@@ -633,10 +628,6 @@ def catalog():
633
  <i class="fas fa-tag"></i>
634
  Скидки
635
  </a>
636
- <a href="#" onclick="openAddressModal()">
637
- <i class="fas fa-map-marker-alt"></i>
638
- Адрес
639
- </a>
640
  <a href="https://api.whatsapp.com/send?phone=996500654659">
641
  <i class="fab fa-whatsapp"></i>
642
  WhatsApp
@@ -839,33 +830,25 @@ def catalog():
839
  });
840
  }
841
 
842
- function openAddressModal() {
843
- document.getElementById('addressModal').style.display = 'block';
844
- }
845
 
846
  window.onclick = function(event) {
847
  if (event.target.className === 'modal') event.target.style.display = "none";
848
  }
849
 
850
  document.getElementById('search-input').addEventListener('input', filterProducts);
851
- document.querySelectorAll('.category-filter').forEach(filter => {
852
- filter.addEventListener('click', function() {
853
- document.querySelectorAll('.category-filter').forEach(f => f.classList.remove('active'));
854
- this.classList.add('active');
855
- filterProducts();
856
- });
857
- });
858
 
859
  function filterProducts() {
860
  const searchTerm = document.getElementById('search-input').value.toLowerCase();
861
- const activeCategory = document.querySelector('.category-filter.active').dataset.category;
862
  document.querySelectorAll('.product').forEach(product => {
863
  const name = product.getAttribute('data-name');
864
  const description = product.getAttribute('data-description');
865
- const category = product.getAttribute('data-category');
866
  const matchesSearch = name.includes(searchTerm) || description.includes(searchTerm);
867
- const matchesCategory = activeCategory === 'all' || category === activeCategory;
868
- product.style.display = matchesSearch && matchesCategory ? 'block' : 'none';
869
  });
870
  }
871
 
@@ -875,7 +858,7 @@ def catalog():
875
  </body>
876
  </html>
877
  '''
878
- return render_template_string(catalog_html, products=products, categories=categories, repo_id=REPO_ID)
879
 
880
  @app.route('/categories')
881
  def categories_page():
@@ -1028,22 +1011,13 @@ def categories_page():
1028
  </div>
1029
  <div class="categories-grid">
1030
  {% for category in categories %}
1031
- <a href="/category/{{ category }}" class="category-item">
1032
  <h2>{{ category }}</h2>
1033
  </a>
1034
  {% endfor %}
1035
  </div>
1036
  </div>
1037
 
1038
- <!-- Address Modal -->
1039
- <div id="addressModal" class="modal">
1040
- <div class="modal-content">
1041
- <span class="close" onclick="closeModal('addressModal')">×</span>
1042
- <h2>Наш адрес</h2>
1043
- <p>Рынок Дордой, Джунхай, 5 проход 505-506 контейнеры</p>
1044
- </div>
1045
- </div>
1046
-
1047
  <div class="navbar">
1048
  <a href="/">
1049
  <i class="fas fa-home"></i>
@@ -1061,10 +1035,6 @@ def categories_page():
1061
  <i class="fas fa-tag"></i>
1062
  Скидки
1063
  </a>
1064
- <a href="#" onclick="openAddressModal()">
1065
- <i class="fas fa-map-marker-alt"></i>
1066
- Адрес
1067
- </a>
1068
  <a href="https://api.whatsapp.com/send?phone=996500654659">
1069
  <i class="fab fa-whatsapp"></i>
1070
  WhatsApp
@@ -1085,14 +1055,6 @@ def categories_page():
1085
  document.querySelector('.theme-toggle i').classList.replace('fa-moon', 'fa-sun');
1086
  }
1087
 
1088
- function openAddressModal() {
1089
- document.getElementById('addressModal').style.display = 'block';
1090
- }
1091
-
1092
- function closeModal(modalId) {
1093
- document.getElementById(modalId).style.display = "none";
1094
- }
1095
-
1096
  window.onclick = function(event) {
1097
  if (event.target.className === 'modal') event.target.style.display = "none";
1098
  }
@@ -1106,8 +1068,8 @@ def categories_page():
1106
  def category_products(category):
1107
  data = load_data()
1108
  products = [p for p in data['products'] if p.get('category') == category]
1109
- categories = data['categories']
1110
-
1111
  category_html = '''
1112
  <!DOCTYPE html>
1113
  <html lang="ru">
@@ -1119,6 +1081,7 @@ def category_products(category):
1119
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
1120
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
1121
  <style>
 
1122
  * {
1123
  margin: 0;
1124
  padding: 0;
@@ -1474,6 +1437,7 @@ def category_products(category):
1474
  font-size: 0.75rem;
1475
  font-weight: 500;
1476
  }
 
1477
  </style>
1478
  </head>
1479
  <body>
@@ -1560,15 +1524,6 @@ def category_products(category):
1560
  </div>
1561
  </div>
1562
 
1563
- <!-- Address Modal -->
1564
- <div id="addressModal" class="modal">
1565
- <div class="modal-content">
1566
- <span class="close" onclick="closeModal('addressModal')">×</span>
1567
- <h2>Наш адрес</h2>
1568
- <p>Рынок Дордой, Джунхай, 5 проход 505-506 контейнеры</p>
1569
- </div>
1570
- </div>
1571
-
1572
  <button id="cart-button" onclick="openCartModal()">🛒</button>
1573
 
1574
  <div class="navbar">
@@ -1588,10 +1543,7 @@ def category_products(category):
1588
  <i class="fas fa-tag"></i>
1589
  Скидки
1590
  </a>
1591
- <a href="#" onclick="openAddressModal()">
1592
- <i class="fas fa-map-marker-alt"></i>
1593
- Адрес
1594
- </a>
1595
  <a href="https://api.whatsapp.com/send?phone=996500654659">
1596
  <i class="fab fa-whatsapp"></i>
1597
  WhatsApp
@@ -1794,9 +1746,6 @@ def category_products(category):
1794
  });
1795
  }
1796
 
1797
- function openAddressModal() {
1798
- document.getElementById('addressModal').style.display = 'block';
1799
- }
1800
 
1801
  window.onclick = function(event) {
1802
  if (event.target.className === 'modal') event.target.style.display = "none";
@@ -1810,12 +1759,13 @@ def category_products(category):
1810
  '''
1811
  return render_template_string(category_html, products=products, category=category, repo_id=REPO_ID)
1812
 
 
1813
  @app.route('/favorites')
1814
  def favorites_page():
1815
  data = load_data()
1816
  products = data['products']
1817
- favorites = request.args.get('favorites', '[]')
1818
-
1819
  favorites_html = '''
1820
  <!DOCTYPE html>
1821
  <html lang="ru">
@@ -1827,6 +1777,7 @@ def favorites_page():
1827
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
1828
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
1829
  <style>
 
1830
  * {
1831
  margin: 0;
1832
  padding: 0;
@@ -2229,14 +2180,6 @@ def favorites_page():
2229
  </div>
2230
  </div>
2231
 
2232
- <!-- Address Modal -->
2233
- <div id="addressModal" class="modal">
2234
- <div class="modal-content">
2235
- <span class="close" onclick="closeModal('addressModal')">×</span>
2236
- <h2>Наш адрес</h2>
2237
- <p>Рынок Дордой, Джунхай, 5 проход 505-506 контейнеры</p>
2238
- </div>
2239
- </div>
2240
 
2241
  <button id="cart-button" onclick="openCartModal()">🛒</button>
2242
 
@@ -2257,10 +2200,6 @@ def favorites_page():
2257
  <i class="fas fa-tag"></i>
2258
  Скидки
2259
  </a>
2260
- <a href="#" onclick="openAddressModal()">
2261
- <i class="fas fa-map-marker-alt"></i>
2262
- Адрес
2263
- </a>
2264
  <a href="https://api.whatsapp.com/send?phone=996500654659">
2265
  <i class="fab fa-whatsapp"></i>
2266
  WhatsApp
@@ -2299,7 +2238,7 @@ def favorites_page():
2299
 
2300
  favorites.forEach(index => {
2301
  const product = products[index];
2302
- if (!product) return;
2303
  const productElement = document.createElement('div');
2304
  productElement.className = 'product';
2305
  productElement.setAttribute('onclick', `openModal(${index})`);
@@ -2495,11 +2434,7 @@ def favorites_page():
2495
  favoriteButton.classList.add('favorited');
2496
  }
2497
  localStorage.setItem('favorites', JSON.stringify(favorites));
2498
- loadFavoritesPage();
2499
- }
2500
-
2501
- function openAddressModal() {
2502
- document.getElementById('addressModal').style.display = 'block';
2503
  }
2504
 
2505
  window.onclick = function(event) {
@@ -2507,19 +2442,21 @@ def favorites_page():
2507
  }
2508
 
2509
  updateCartButton();
2510
- loadFavoritesPage();
2511
  </script>
2512
  </body>
2513
  </html>
2514
  '''
2515
  return render_template_string(favorites_html, products=products, repo_id=REPO_ID)
2516
 
 
 
2517
  @app.route('/discounts')
2518
  def discounts_page():
2519
  data = load_data()
2520
  products = [p for p in data['products'] if p.get('discount')]
2521
- categories = data['categories']
2522
-
2523
  discounts_html = '''
2524
  <!DOCTYPE html>
2525
  <html lang="ru">
@@ -2531,6 +2468,7 @@ def discounts_page():
2531
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
2532
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
2533
  <style>
 
2534
  * {
2535
  margin: 0;
2536
  padding: 0;
@@ -2972,15 +2910,6 @@ def discounts_page():
2972
  </div>
2973
  </div>
2974
 
2975
- <!-- Address Modal -->
2976
- <div id="addressModal" class="modal">
2977
- <div class="modal-content">
2978
- <span class="close" onclick="closeModal('addressModal')">×</span>
2979
- <h2>Наш адрес</h2>
2980
- <p>Рынок Дордой, Джунхай, 5 проход 505-506 контейнеры</p>
2981
- </div>
2982
- </div>
2983
-
2984
  <button id="cart-button" onclick="openCartModal()">🛒</button>
2985
 
2986
  <div class="navbar">
@@ -3000,10 +2929,6 @@ def discounts_page():
3000
  <i class="fas fa-tag"></i>
3001
  Скидки
3002
  </a>
3003
- <a href="#" onclick="openAddressModal()">
3004
- <i class="fas fa-map-marker-alt"></i>
3005
- Адрес
3006
- </a>
3007
  <a href="https://api.whatsapp.com/send?phone=996500654659">
3008
  <i class="fab fa-whatsapp"></i>
3009
  WhatsApp
@@ -3206,10 +3131,6 @@ def discounts_page():
3206
  });
3207
  }
3208
 
3209
- function openAddressModal() {
3210
- document.getElementById('addressModal').style.display = 'block';
3211
- }
3212
-
3213
  window.onclick = function(event) {
3214
  if (event.target.className === 'modal') event.target.style.display = "none";
3215
  }
@@ -3220,15 +3141,19 @@ def discounts_page():
3220
  </body>
3221
  </html>
3222
  '''
3223
- return render_template_string(discounts_html, products=products, categories=categories, repo_id=REPO_ID)
 
3224
 
3225
  @app.route('/product/<int:index>')
3226
  def product_details(index):
3227
  data = load_data()
 
 
3228
  product = data['products'][index]
3229
-
3230
  product_html = '''
3231
  <style>
 
3232
  .swiper-container {
3233
  width: 100%;
3234
  max-width: 400px;
@@ -3300,7 +3225,7 @@ def product_details(index):
3300
  font-size: 0.9rem;
3301
  }
3302
  body.dark-mode .product-details .colors span {
3303
- background: #444;
3304
  color: #e0e0e0;
3305
  }
3306
  </style>
@@ -3388,7 +3313,7 @@ def admin():
3388
  elif action == 'edit':
3389
  index = int(request.form['index'])
3390
  photos = request.files.getlist('photos')
3391
- photo_filenames = products[index].get('photos', [])
3392
  for photo in photos:
3393
  if photo and photo.filename:
3394
  filename = secure_filename(photo.filename)
@@ -3400,7 +3325,7 @@ def admin():
3400
  repo_type="dataset",
3401
  token=HF_TOKEN_WRITE
3402
  )
3403
- photo_filenames.append(filename)
3404
 
3405
  colors = request.form.getlist('colors')
3406
  colors = [color.strip() for color in colors if color.strip()]
@@ -3413,13 +3338,28 @@ def admin():
3413
  'description': request.form['description'],
3414
  'category': request.form['category'],
3415
  'colors': colors,
3416
- 'photos': photo_filenames,
3417
  'discount': float(request.form['discount']) if request.form['discount'] else None
3418
  }
3419
 
3420
  elif action == 'delete':
3421
  index = int(request.form['index'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3422
  products.pop(index)
 
3423
 
3424
  elif action == 'add_category':
3425
  category = request.form['category_name'].strip()
@@ -3430,6 +3370,7 @@ def admin():
3430
  index = int(request.form['category_index'])
3431
  category_to_delete = categories[index]
3432
  categories.pop(index)
 
3433
  for product in products:
3434
  if product.get('category') == category_to_delete:
3435
  product['category'] = 'Без категории'
@@ -3446,6 +3387,7 @@ def admin():
3446
  <title>Админ-панель</title>
3447
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
3448
  <style>
 
3449
  * {
3450
  margin: 0;
3451
  padding: 0;
@@ -3766,5 +3708,4 @@ if __name__ == '__main__':
3766
  load_data()
3767
  except Exception as e:
3768
  logging.error(f"Не удалось загрузить базу данных: {e}")
3769
- app.run(debug=True, host='0.0.0.0', port=7860)
3770
-
 
13
  DATA_FILE = 'data_kanc.json'
14
 
15
  # Настройки Hugging Face
16
+ REPO_ID = "Kgshop/clients" # Замените, если нужно
17
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
18
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
19
 
 
27
  data = json.load(file)
28
  logging.info("Данные успешно загружены из JSON")
29
  if not isinstance(data, dict) or 'products' not in data or 'categories' not in data:
30
+ return {'products': [], 'categories': []} # Corrected: return empty dict with lists
31
  return data
32
  except FileNotFoundError:
33
  logging.warning("Локальный файл базы данных не найден после скачивания.")
 
94
  def catalog():
95
  data = load_data()
96
  products = data['products']
97
+ # categories = data['categories'] Removed categories from main page
98
+
99
  catalog_html = '''
100
  <!DOCTYPE html>
101
  <html lang="ru">
 
107
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
108
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
109
  <style>
110
+ /* ... (your existing styles) ... */
111
  * {
112
  margin: 0;
113
  padding: 0;
 
159
  body.dark-mode .theme-toggle {
160
  color: #bbb;
161
  }
162
+ /* Removed .filters-container */
 
 
 
 
 
 
163
  .search-container {
164
  margin: 20px 0;
165
  text-align: center;
 
179
  border-color: #526df2;
180
  box-shadow: 0 4px 15px rgba(82, 109, 242, 0.2);
181
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  .products-grid {
183
  display: grid;
184
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
185
  gap: 20px;
186
  padding: 10px;
187
  }
188
+ /* ... (rest of your product and modal styles) ... */
189
  .product {
190
  background: rgba(255, 255, 255, 0.8);
191
  border: 1px solid rgba(0, 0, 0, 0.05);
 
484
  font-size: 0.75rem;
485
  font-weight: 500;
486
  }
487
+
488
+ /* Styles for Address and Schedule */
489
+ .info-section {
490
+ text-align: center;
491
+ margin: 20px 0;
492
+ padding: 15px;
493
+ background: rgba(255, 255, 255, 0.8);
494
+ border-radius: 15px;
495
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
496
+ }
497
+ body.dark-mode .info-section {
498
+ background: rgba(42, 42, 62, 0.8);
499
+ }
500
+ .info-section h2 {
501
+ font-size: 1.5rem;
502
+ font-weight: 500;
503
+ margin-bottom: 10px;
504
+ color: #526df2;
505
+ }
506
+ .info-section p {
507
+ font-size: 1rem;
508
+ color: #666;
509
+ }
510
+ body.dark-mode .info-section p {
511
+ color: #bbb;
512
+ }
513
  </style>
514
  </head>
515
  <body>
 
520
  <i class="fas fa-moon"></i>
521
  </button>
522
  </div>
523
+
524
+ <!-- Address and Schedule Section -->
525
+ <div class="info-section">
526
+ <h2>Наш адрес</h2>
527
+ <p>Рынок Дордой, Джунхай, 5 проход 505-506 контейнеры</p>
528
+ <h2>График работы</h2>
529
+ <p>С 9:00 до 16:00 без выходных</p>
530
  </div>
531
+
532
  <div class="search-container">
533
  <input type="text" id="search-input" placeholder="Поиск товаров...">
534
  </div>
 
608
  </div>
609
  </div>
610
 
 
 
 
 
 
 
 
 
 
611
  <button id="cart-button" onclick="openCartModal()">🛒</button>
612
 
613
  <!-- Navigation Bar -->
 
628
  <i class="fas fa-tag"></i>
629
  Скидки
630
  </a>
 
 
 
 
631
  <a href="https://api.whatsapp.com/send?phone=996500654659">
632
  <i class="fab fa-whatsapp"></i>
633
  WhatsApp
 
830
  });
831
  }
832
 
833
+ // Removed openAddressModal function
 
 
834
 
835
  window.onclick = function(event) {
836
  if (event.target.className === 'modal') event.target.style.display = "none";
837
  }
838
 
839
  document.getElementById('search-input').addEventListener('input', filterProducts);
840
+ // Removed category filter event listeners
 
 
 
 
 
 
841
 
842
  function filterProducts() {
843
  const searchTerm = document.getElementById('search-input').value.toLowerCase();
844
+ // Removed activeCategory check
845
  document.querySelectorAll('.product').forEach(product => {
846
  const name = product.getAttribute('data-name');
847
  const description = product.getAttribute('data-description');
848
+ // const category = product.getAttribute('data-category'); // Kept for potential use
849
  const matchesSearch = name.includes(searchTerm) || description.includes(searchTerm);
850
+ // Removed category matching
851
+ product.style.display = matchesSearch ? 'block' : 'none'; //Simplified condition
852
  });
853
  }
854
 
 
858
  </body>
859
  </html>
860
  '''
861
+ return render_template_string(catalog_html, products=products, repo_id=REPO_ID)
862
 
863
  @app.route('/categories')
864
  def categories_page():
 
1011
  </div>
1012
  <div class="categories-grid">
1013
  {% for category in categories %}
1014
+ <a href="{{ url_for('category_products', category=category) }}" class="category-item">
1015
  <h2>{{ category }}</h2>
1016
  </a>
1017
  {% endfor %}
1018
  </div>
1019
  </div>
1020
 
 
 
 
 
 
 
 
 
 
1021
  <div class="navbar">
1022
  <a href="/">
1023
  <i class="fas fa-home"></i>
 
1035
  <i class="fas fa-tag"></i>
1036
  Скидки
1037
  </a>
 
 
 
 
1038
  <a href="https://api.whatsapp.com/send?phone=996500654659">
1039
  <i class="fab fa-whatsapp"></i>
1040
  WhatsApp
 
1055
  document.querySelector('.theme-toggle i').classList.replace('fa-moon', 'fa-sun');
1056
  }
1057
 
 
 
 
 
 
 
 
 
1058
  window.onclick = function(event) {
1059
  if (event.target.className === 'modal') event.target.style.display = "none";
1060
  }
 
1068
  def category_products(category):
1069
  data = load_data()
1070
  products = [p for p in data['products'] if p.get('category') == category]
1071
+ # categories = data['categories'] # No longer needed here
1072
+
1073
  category_html = '''
1074
  <!DOCTYPE html>
1075
  <html lang="ru">
 
1081
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
1082
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
1083
  <style>
1084
+ /* ... (your existing styles for product display) ... */
1085
  * {
1086
  margin: 0;
1087
  padding: 0;
 
1437
  font-size: 0.75rem;
1438
  font-weight: 500;
1439
  }
1440
+
1441
  </style>
1442
  </head>
1443
  <body>
 
1524
  </div>
1525
  </div>
1526
 
 
 
 
 
 
 
 
 
 
1527
  <button id="cart-button" onclick="openCartModal()">🛒</button>
1528
 
1529
  <div class="navbar">
 
1543
  <i class="fas fa-tag"></i>
1544
  Скидки
1545
  </a>
1546
+
 
 
 
1547
  <a href="https://api.whatsapp.com/send?phone=996500654659">
1548
  <i class="fab fa-whatsapp"></i>
1549
  WhatsApp
 
1746
  });
1747
  }
1748
 
 
 
 
1749
 
1750
  window.onclick = function(event) {
1751
  if (event.target.className === 'modal') event.target.style.display = "none";
 
1759
  '''
1760
  return render_template_string(category_html, products=products, category=category, repo_id=REPO_ID)
1761
 
1762
+
1763
  @app.route('/favorites')
1764
  def favorites_page():
1765
  data = load_data()
1766
  products = data['products']
1767
+ favorites = request.args.get('favorites', '[]') # Not really used directly, but kept for consistency
1768
+
1769
  favorites_html = '''
1770
  <!DOCTYPE html>
1771
  <html lang="ru">
 
1777
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
1778
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
1779
  <style>
1780
+ /* ... (your existing styles for product display) ... */
1781
  * {
1782
  margin: 0;
1783
  padding: 0;
 
2180
  </div>
2181
  </div>
2182
 
 
 
 
 
 
 
 
 
2183
 
2184
  <button id="cart-button" onclick="openCartModal()">🛒</button>
2185
 
 
2200
  <i class="fas fa-tag"></i>
2201
  Скидки
2202
  </a>
 
 
 
 
2203
  <a href="https://api.whatsapp.com/send?phone=996500654659">
2204
  <i class="fab fa-whatsapp"></i>
2205
  WhatsApp
 
2238
 
2239
  favorites.forEach(index => {
2240
  const product = products[index];
2241
+ if (!product) return; //Important check in case product was deleted
2242
  const productElement = document.createElement('div');
2243
  productElement.className = 'product';
2244
  productElement.setAttribute('onclick', `openModal(${index})`);
 
2434
  favoriteButton.classList.add('favorited');
2435
  }
2436
  localStorage.setItem('favorites', JSON.stringify(favorites));
2437
+ loadFavoritesPage(); // Reload the favorites page after toggling
 
 
 
 
2438
  }
2439
 
2440
  window.onclick = function(event) {
 
2442
  }
2443
 
2444
  updateCartButton();
2445
+ loadFavoritesPage(); // Load favorites on initial page load
2446
  </script>
2447
  </body>
2448
  </html>
2449
  '''
2450
  return render_template_string(favorites_html, products=products, repo_id=REPO_ID)
2451
 
2452
+
2453
+
2454
  @app.route('/discounts')
2455
  def discounts_page():
2456
  data = load_data()
2457
  products = [p for p in data['products'] if p.get('discount')]
2458
+ # categories = data['categories'] # No longer used in this view
2459
+
2460
  discounts_html = '''
2461
  <!DOCTYPE html>
2462
  <html lang="ru">
 
2468
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
2469
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
2470
  <style>
2471
+ /* ... (your existing styles for product display) ... */
2472
  * {
2473
  margin: 0;
2474
  padding: 0;
 
2910
  </div>
2911
  </div>
2912
 
 
 
 
 
 
 
 
 
 
2913
  <button id="cart-button" onclick="openCartModal()">🛒</button>
2914
 
2915
  <div class="navbar">
 
2929
  <i class="fas fa-tag"></i>
2930
  Скидки
2931
  </a>
 
 
 
 
2932
  <a href="https://api.whatsapp.com/send?phone=996500654659">
2933
  <i class="fab fa-whatsapp"></i>
2934
  WhatsApp
 
3131
  });
3132
  }
3133
 
 
 
 
 
3134
  window.onclick = function(event) {
3135
  if (event.target.className === 'modal') event.target.style.display = "none";
3136
  }
 
3141
  </body>
3142
  </html>
3143
  '''
3144
+ return render_template_string(discounts_html, products=products, repo_id=REPO_ID)
3145
+
3146
 
3147
  @app.route('/product/<int:index>')
3148
  def product_details(index):
3149
  data = load_data()
3150
+ if index < 0 or index >= len(data['products']):
3151
+ return "Product not found", 404 # Return a 404 error if index is out of bounds
3152
  product = data['products'][index]
3153
+
3154
  product_html = '''
3155
  <style>
3156
+ /* ... (your existing styles for product details modal) ... */
3157
  .swiper-container {
3158
  width: 100%;
3159
  max-width: 400px;
 
3225
  font-size: 0.9rem;
3226
  }
3227
  body.dark-mode .product-details .colors span {
3228
+ background: #
3229
  color: #e0e0e0;
3230
  }
3231
  </style>
 
3313
  elif action == 'edit':
3314
  index = int(request.form['index'])
3315
  photos = request.files.getlist('photos')
3316
+ photo_filenames = products[index].get('photos', []) # Keep existing photos
3317
  for photo in photos:
3318
  if photo and photo.filename:
3319
  filename = secure_filename(photo.filename)
 
3325
  repo_type="dataset",
3326
  token=HF_TOKEN_WRITE
3327
  )
3328
+ photo_filenames.append(filename) # Add new photos
3329
 
3330
  colors = request.form.getlist('colors')
3331
  colors = [color.strip() for color in colors if color.strip()]
 
3338
  'description': request.form['description'],
3339
  'category': request.form['category'],
3340
  'colors': colors,
3341
+ 'photos': photo_filenames, # Updated photo list
3342
  'discount': float(request.form['discount']) if request.form['discount'] else None
3343
  }
3344
 
3345
  elif action == 'delete':
3346
  index = int(request.form['index'])
3347
+ # Delete photos from Hugging Face Hub before deleting the product
3348
+ product_to_delete = products[index]
3349
+ if 'photos' in product_to_delete:
3350
+ api = HfApi()
3351
+ for photo in product_to_delete['photos']:
3352
+ try:
3353
+ api.delete_file(
3354
+ path_in_repo=f"photos/{photo}",
3355
+ repo_id=REPO_ID,
3356
+ repo_type="dataset",
3357
+ token=HF_TOKEN_WRITE
3358
+ )
3359
+ except Exception as e:
3360
+ logging.error(f"Error deleting photo {photo}: {e}")
3361
  products.pop(index)
3362
+
3363
 
3364
  elif action == 'add_category':
3365
  category = request.form['category_name'].strip()
 
3370
  index = int(request.form['category_index'])
3371
  category_to_delete = categories[index]
3372
  categories.pop(index)
3373
+ #Set category to "Без категории" for products in the deleted category
3374
  for product in products:
3375
  if product.get('category') == category_to_delete:
3376
  product['category'] = 'Без категории'
 
3387
  <title>Админ-панель</title>
3388
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
3389
  <style>
3390
+ /* ... (your existing admin panel styles) ... */
3391
  * {
3392
  margin: 0;
3393
  padding: 0;
 
3708
  load_data()
3709
  except Exception as e:
3710
  logging.error(f"Не удалось загрузить базу данных: {e}")
3711
+ app.run(debug=True, host='0.0.0.0', port=7860)