Kgshop commited on
Commit
88dd0bd
·
verified ·
1 Parent(s): 96581ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -7
app.py CHANGED
@@ -46,7 +46,8 @@ LANGUAGES = {
46
  'pl': 'Polski',
47
  'uk': 'Українська',
48
  'zh': '中文',
49
- 'en': 'English'
 
50
  }
51
 
52
  TRANSLATIONS = {
@@ -257,6 +258,58 @@ TRANSLATIONS = {
257
  'arch_item_conf': 'Archive this item?', 'del_folder_conf': 'Delete folder? Photos remain.',
258
  'del_card_conf': 'Delete card?', 'viewed': 'Viewed', 'new_ord': 'New',
259
  'saving_data': 'Please wait...<br>Saving data', 'order_hash': 'Order #'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  }
261
  }
262
 
@@ -720,6 +773,9 @@ CATALOG_TEMPLATE = '''
720
 
721
  .main-wrapper { max-width: 680px; margin: 0 auto; padding: 40px 20px 90px 20px; display: flex; flex-direction: column; align-items: center; position: relative; }
722
 
 
 
 
723
  .qr-btn { position: absolute; top: 20px; right: 20px; font-size: 1.5rem; color: var(--accent); background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 100; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
724
  .qr-btn:hover { background: var(--accent); color: var(--text-dark); transform: scale(1.1); box-shadow: 0 8px 24px rgba(0,0,0,0.2); }
725
 
@@ -735,6 +791,10 @@ CATALOG_TEMPLATE = '''
735
  .save-contact-btn:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0,0,0,0.3); background: var(--accent-hover); }
736
  .save-contact-btn:active { transform: translateY(0); box-shadow: 0 4px 15px rgba(0,0,0,0.2); }
737
 
 
 
 
 
738
  .blocks-container { width: 100%; display: flex; flex-direction: column; gap: 16px; margin-bottom: 45px; }
739
  .block-link { display: flex; align-items: center; justify-content: center; position: relative; background: var(--card-bg); color: var(--text-light); text-align: center; padding: 20px 24px; border-radius: 24px; text-decoration: none; font-weight: 600; font-size: 1.15rem; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--border-color); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); min-height: 70px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
740
  .block-link:hover { transform: translateY(-3px) scale(1.02); background: var(--bg-medium); border-color: var(--accent); box-shadow: 0 8px 25px rgba(0,0,0,0.2); }
@@ -838,6 +898,9 @@ CATALOG_TEMPLATE = '''
838
  <body class="{{ 'dark-theme' if settings.color_scheme in['dark', 'cyberpunk', 'neon', 'volcano', 'gold', 'monochrome_dark', 'nord', 'dracula', 'ruby', 'sapphire', 'amethyst', 'cosmic', 'crimson', 'mocha', 'minty', 'solar'] else '' }}">
839
 
840
  <div class="main-wrapper">
 
 
 
841
  <div class="qr-btn" onclick="openQrModal()">
842
  <i class="fas fa-qrcode"></i>
843
  </div>
@@ -931,6 +994,18 @@ CATALOG_TEMPLATE = '''
931
  <button class="clear-cart-btn" style="width: 100%; text-align: center;" onclick="clearFilter()">{{ t('reset_all', lang) }}</button>
932
  </div>
933
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
934
 
935
  <div id="qrModal" class="modal" style="align-items: center;">
936
  <div class="qr-modal-content">
@@ -1152,6 +1227,11 @@ CATALOG_TEMPLATE = '''
1152
  document.body.style.overflow = 'hidden';
1153
  }
1154
 
 
 
 
 
 
1155
  function applyFilter() {
1156
  let minVal = parseFloat(document.getElementById('minPriceInput').value);
1157
  let maxVal = parseFloat(document.getElementById('maxPriceInput').value);
@@ -2737,7 +2817,12 @@ def catalog(env_id):
2737
  all_products = data.get('products',[])
2738
  settings = data.get('settings', {})
2739
  blocks = data.get('blocks',[])
2740
- lang = settings.get('site_language', 'pl')
 
 
 
 
 
2741
 
2742
  active_products = [p for p in all_products if not p.get('archived', False)]
2743
 
@@ -2757,7 +2842,7 @@ def catalog(env_id):
2757
  return render_template_string(
2758
  CATALOG_TEMPLATE, ordered_categories=ordered_categories,
2759
  products_json=json.dumps(products_sorted_for_js), repo_id=REPO_ID, currency_code=settings.get('currency_code', 'PLN'),
2760
- settings=settings, chat_avatar_url=chat_avatar_url, env_id=env_id, blocks=blocks, lang=lang
2761
  )
2762
 
2763
  @app.route('/<env_id>/checkout', methods=['POST'])
@@ -2793,7 +2878,11 @@ def order_invoice(env_id, order_id):
2793
  env_data = get_env_data(env_id)
2794
  settings = env_data.get('settings', {})
2795
  orders = env_data.get('orders', [])
2796
- lang = settings.get('site_language', 'pl')
 
 
 
 
2797
 
2798
  order = next((o for o in orders if o.get('id') == order_id), None)
2799
  if not order:
@@ -2835,7 +2924,11 @@ def order_invoice(env_id, order_id):
2835
  def admin(env_id):
2836
  data = get_env_data(env_id)
2837
  settings = data.get('settings', {})
2838
- lang = settings.get('site_language', 'pl')
 
 
 
 
2839
 
2840
  if settings.get('admin_password_enabled') and not session.get(f'admin_auth_{env_id}'):
2841
  return redirect(url_for('admin_login', env_id=env_id))
@@ -3070,7 +3163,7 @@ def admin(env_id):
3070
  b_id = request.form.get('block_id')
3071
  block_to_del = next((b for b in blocks if b.get('id') == b_id), None)
3072
  if block_to_del:
3073
- if block_to_del.get('type') == 'pdf' and block_to_del.get('url') and block_to_del.get('url.startswith')('pdf_') and HF_TOKEN_WRITE:
3074
  try:
3075
  HfApi().delete_files(repo_id=REPO_ID, paths_in_repo=[f"pdfs/{block_to_del.get('url')}"], repo_type="dataset", token=HF_TOKEN_WRITE)
3076
  except Exception: pass
@@ -3260,7 +3353,11 @@ def admin(env_id):
3260
  def admin_orders(env_id):
3261
  data = get_env_data(env_id)
3262
  settings = data.get('settings', {})
3263
- lang = settings.get('site_language', 'pl')
 
 
 
 
3264
 
3265
  if settings.get('admin_password_enabled') and not session.get(f'admin_auth_{env_id}'):
3266
  return redirect(url_for('admin_login', env_id=env_id))
 
46
  'pl': 'Polski',
47
  'uk': 'Українська',
48
  'zh': '中文',
49
+ 'en': 'English',
50
+ 'tr': 'Türkçe'
51
  }
52
 
53
  TRANSLATIONS = {
 
258
  'arch_item_conf': 'Archive this item?', 'del_folder_conf': 'Delete folder? Photos remain.',
259
  'del_card_conf': 'Delete card?', 'viewed': 'Viewed', 'new_ord': 'New',
260
  'saving_data': 'Please wait...<br>Saving data', 'order_hash': 'Order #'
261
+ },
262
+ 'tr': {
263
+ 'login': 'Giriş', 'admin_panel': 'Yönetici Paneli', 'enter_pwd': 'Şifreyi girin',
264
+ 'sign_in': 'Giriş yap', 'card_mgmt': 'Kart Yönetimi', 'create_card': 'Yeni kart oluştur',
265
+ 'search_id_name': 'ID veya İsme göre ara...', 'existing_cards': 'Mevcut kartlar',
266
+ 'settings': 'Ayarlar', 'view': 'Görüntüle', 'delete': 'Sil', 'enable_pwd': 'Şifreyi etkinleştir',
267
+ 'pwd': 'Şifre', 'save': 'Kaydet', 'no_cards': 'Henüz kart oluşturulmadı.',
268
+ 'save_contacts': 'Kişilere kaydet', 'search_placeholder': 'Ara...', 'all': 'Tümü',
269
+ 'min': 'Min', 'max': 'Maks', 'apply_filter': 'Uygula', 'reset_all': 'Sıfırla',
270
+ 'price_from': 'Başlangıç fiyatı:', 'price_to': 'Bitiş fiyatı:', 'my_qr': 'QR Kodum', 'scan_qr': 'Kartı açmak için tarayın',
271
+ 'cart': 'Sepet', 'clear': 'Temizle', 'total': 'Toplam:', 'checkout': 'Ödeme',
272
+ 'your_name': 'Adınız', 'your_phone': 'Telefonunuz', 'confirm_order': 'Siparişi onayla',
273
+ 'cart_empty': 'Sepetiniz boş', 'variant': 'Varyant:', 'add_to_cart': 'Sepete ekle',
274
+ 'site_settings': 'Site Ayarları', 'orders': 'Siparişler', 'save_qr': 'QR Kaydet',
275
+ 'logout': 'Çıkış', 'profile_app': 'Profil ve Görünüm', 'first_name': 'Ad:',
276
+ 'last_name': 'Soyad:', 'profession': 'Meslek / Ünvan:', 'org_name': 'Kurum Adı:',
277
+ 'about_me': 'Hakkımda:', 'avatar': 'Avatar:', 'current': 'Mevcut:', 'design': 'Tasarım:',
278
+ 'currency': 'Site Para Birimi:', 'order_recv': 'Sipariş Alımı', 'enable_ord': 'Siparişi etkinleştir',
279
+ 'where_recv': 'Nereye alınacak:', 'to_wa': 'WhatsApp', 'to_tg': 'Telegram',
280
+ 'no_recv': 'Alma', 'your_num': 'Numaranız/Kullanıcı adınız:', 'pwd_login': 'Giriş şifresi',
281
+ 'enable_pwd_prompt': 'Şifre sormayı etkinleştir', 'save_settings': 'Ayarları kaydet',
282
+ 'btn_links': 'Butonlar ve Bağlantılar', 'create_btn': 'Buton oluştur', 'btn_type': 'Buton tipi:',
283
+ 'reg_link': 'Normal link/numara', 'txt_desc': 'Metin (açıklama)', 'open_pdf': 'PDF Aç',
284
+ 'btn_text': 'Buton metni (başlık):', 'btn_icon': 'İkon:', 'no_icon': '-- İkon yok --',
285
+ 'link_phone': 'Link/telefon (+ ile):', 'sel_pdf': 'PDF seç:', 'msg_text': 'Mesaj metni:',
286
+ 'add_btn': 'Buton ekle', 'edit': 'Düzenle', 'up': 'Yukarı', 'down': 'Aşağı',
287
+ 'save_changes': 'Değişiklikleri kaydet', 'folders': 'Klasörler', 'create_folder': 'Klasör oluştur',
288
+ 'new_folder_name': 'Klasör adı:', 'del_folder': 'Klasörü sil', 'no_folders': 'Klasör yok.',
289
+ 'all_photos': 'Tüm fotoğraflar ve ürünler', 'upload_multi': 'Çoklu fotoğraf yükle',
290
+ 'folder_to_add': 'Hedef klasör:', 'no_folder': 'Klasörsüz', 'uncat': 'Kategorisiz',
291
+ 'sel_photos': 'Fotoğrafları seç:', 'publish': 'Yayınla', 'active': 'Aktif',
292
+ 'archive': 'Arşiv', 'select': 'Seç', 'folder': 'Klasör:', 'price': 'Fiyat:',
293
+ 'desc': 'Açıklama:', 'variants': 'Varyantlar:', 'keywords': 'Anahtar kelimeler:',
294
+ 'to_archive': 'Arşive gönder', 'restore': 'Geri yükle', 'new_price': 'Yeni fiyat:',
295
+ 'move_folder': 'Şuraya taşı:', 'desc_opt': 'Açıklama (opsiyonel):', 'search_words': 'Arama kelimeleri:',
296
+ 'var_format': 'Varyantlar (Ad:Fiyat):', 'up_new_photos': 'Yeni fotoğraflar yükle:',
297
+ 'back': 'Geri', 'forward': 'İleri', 'group': 'Grupla', 'order_inv': 'Sipariş Faturası',
298
+ 'customer': 'Müşteri:', 'phone': 'Telefon:', 'seller': 'Satıcı:', 'pcs': 'adet',
299
+ 'send_seller': 'Satıcıya gönder', 'back_cat': 'Kataloğa dön', 'order_hist': 'Sipariş geçmişi',
300
+ 'back_settings': 'Ayarlara dön', 'invoice': 'Fatura', 'lang': 'Dil',
301
+ 'site_lang': 'Site Dili:', 'no_photo': 'Fotoğraf yok', 'from': 'Başlangıç',
302
+ 'nothing_found': 'Hiçbir şey bulunamadı.', 'price_filter': 'Fiyat filtresi',
303
+ 'order_proc': 'İşleniyor...', 'net_err': 'Ağ hatası', 'order_err': 'Sipariş hatası',
304
+ 'fill_name_phone': 'Lütfen adınızı ve telefonunuzu doldurun', 'cart_empty_alert': 'Sepet boş',
305
+ 'clear_cart_conf': 'Sepeti temizlemek istiyor musunuz?', 'upload_err': 'Yükleme hatası.',
306
+ 'uploading': 'Yükleniyor...', 'prep_files': 'Dosyalar hazırlanıyor...',
307
+ 'pls_sel_photos': 'Lütfen önce fotoğrafları seçin!', 'del_btn_conf': 'Bu butonu silmek istiyor musunuz?',
308
+ 'restore_conf': 'Bu öğeleri geri yüklemek istiyor musunuz?', 'archive_conf': 'Bu öğeleri arşive taşımak istiyor musunuz?',
309
+ 'del_all_conf': 'Kalıcı olarak silinsin mi?', 'del_item_conf': 'Bu öğeyi silmek istiyor musunuz?',
310
+ 'arch_item_conf': 'Bu öğeyi arşive taşımak istiyor musunuz?', 'del_folder_conf': 'Klasör silinsin mi? Fotoğraflar kalacaktır.',
311
+ 'del_card_conf': 'Kart silinsin mi?', 'viewed': 'Görüldü', 'new_ord': 'Yeni',
312
+ 'saving_data': 'Lütfen bekleyin...<br>Veriler kaydediliyor', 'order_hash': 'Sipariş #'
313
  }
314
  }
315
 
 
773
 
774
  .main-wrapper { max-width: 680px; margin: 0 auto; padding: 40px 20px 90px 20px; display: flex; flex-direction: column; align-items: center; position: relative; }
775
 
776
+ .lang-btn { position: absolute; top: 20px; left: 20px; font-size: 1.2rem; color: var(--accent); background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 100; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
777
+ .lang-btn:hover { background: var(--accent); color: var(--text-dark); transform: scale(1.1); box-shadow: 0 8px 24px rgba(0,0,0,0.2); }
778
+
779
  .qr-btn { position: absolute; top: 20px; right: 20px; font-size: 1.5rem; color: var(--accent); background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 50%; width: 45px; height: 45px; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); z-index: 100; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
780
  .qr-btn:hover { background: var(--accent); color: var(--text-dark); transform: scale(1.1); box-shadow: 0 8px 24px rgba(0,0,0,0.2); }
781
 
 
791
  .save-contact-btn:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0,0,0,0.3); background: var(--accent-hover); }
792
  .save-contact-btn:active { transform: translateY(0); box-shadow: 0 4px 15px rgba(0,0,0,0.2); }
793
 
794
+ .lang-option-btn { width: 100%; padding: 15px; margin-bottom: 10px; font-size: 1.1rem; border-radius: 16px; background: var(--card-bg); color: var(--text-light); border: 1px solid var(--border-color); cursor: pointer; transition: all 0.3s; font-weight: 600; text-align: center; display: block; }
795
+ .lang-option-btn:hover { background: rgba(255,255,255,0.1); transform: translateY(-2px); }
796
+ .lang-option-btn.active-lang { background: var(--accent); color: var(--text-dark); border-color: var(--accent); box-shadow: 0 4px 15px rgba(0,0,0,0.2); }
797
+
798
  .blocks-container { width: 100%; display: flex; flex-direction: column; gap: 16px; margin-bottom: 45px; }
799
  .block-link { display: flex; align-items: center; justify-content: center; position: relative; background: var(--card-bg); color: var(--text-light); text-align: center; padding: 20px 24px; border-radius: 24px; text-decoration: none; font-weight: 600; font-size: 1.15rem; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--border-color); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); min-height: 70px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
800
  .block-link:hover { transform: translateY(-3px) scale(1.02); background: var(--bg-medium); border-color: var(--accent); box-shadow: 0 8px 25px rgba(0,0,0,0.2); }
 
898
  <body class="{{ 'dark-theme' if settings.color_scheme in['dark', 'cyberpunk', 'neon', 'volcano', 'gold', 'monochrome_dark', 'nord', 'dracula', 'ruby', 'sapphire', 'amethyst', 'cosmic', 'crimson', 'mocha', 'minty', 'solar'] else '' }}">
899
 
900
  <div class="main-wrapper">
901
+ <div class="lang-btn" onclick="openLangModal()">
902
+ <i class="fas fa-globe"></i>
903
+ </div>
904
  <div class="qr-btn" onclick="openQrModal()">
905
  <i class="fas fa-qrcode"></i>
906
  </div>
 
994
  <button class="clear-cart-btn" style="width: 100%; text-align: center;" onclick="clearFilter()">{{ t('reset_all', lang) }}</button>
995
  </div>
996
  </div>
997
+
998
+ <div id="langModal" class="modal" style="align-items: center;">
999
+ <div class="qr-modal-content" style="max-width: 320px; text-align: left; padding: 40px 30px;">
1000
+ <button class="close-btn" onclick="closeModal('langModal')" style="top: -15px; right: -15px; background: var(--danger); border-color: var(--danger);"><i class="fas fa-times"></i></button>
1001
+ <h2 style="margin-bottom: 25px; color: var(--accent); text-align: center; font-weight: 800;">{{ t('lang', lang) }}</h2>
1002
+ <div style="display: flex; flex-direction: column; gap: 10px;">
1003
+ {% for code, name in languages.items() %}
1004
+ <button class="lang-option-btn {% if code == lang %}active-lang{% endif %}" onclick="window.location.href='?lang={{ code }}'">{{ name }}</button>
1005
+ {% endfor %}
1006
+ </div>
1007
+ </div>
1008
+ </div>
1009
 
1010
  <div id="qrModal" class="modal" style="align-items: center;">
1011
  <div class="qr-modal-content">
 
1227
  document.body.style.overflow = 'hidden';
1228
  }
1229
 
1230
+ function openLangModal() {
1231
+ document.getElementById('langModal').style.display = 'flex';
1232
+ document.body.style.overflow = 'hidden';
1233
+ }
1234
+
1235
  function applyFilter() {
1236
  let minVal = parseFloat(document.getElementById('minPriceInput').value);
1237
  let maxVal = parseFloat(document.getElementById('maxPriceInput').value);
 
2817
  all_products = data.get('products',[])
2818
  settings = data.get('settings', {})
2819
  blocks = data.get('blocks',[])
2820
+
2821
+ req_lang = request.args.get('lang')
2822
+ if req_lang and req_lang in LANGUAGES:
2823
+ session[f'lang_{env_id}'] = req_lang
2824
+
2825
+ lang = session.get(f'lang_{env_id}', settings.get('site_language', 'pl'))
2826
 
2827
  active_products = [p for p in all_products if not p.get('archived', False)]
2828
 
 
2842
  return render_template_string(
2843
  CATALOG_TEMPLATE, ordered_categories=ordered_categories,
2844
  products_json=json.dumps(products_sorted_for_js), repo_id=REPO_ID, currency_code=settings.get('currency_code', 'PLN'),
2845
+ settings=settings, chat_avatar_url=chat_avatar_url, env_id=env_id, blocks=blocks, lang=lang, languages=LANGUAGES
2846
  )
2847
 
2848
  @app.route('/<env_id>/checkout', methods=['POST'])
 
2878
  env_data = get_env_data(env_id)
2879
  settings = env_data.get('settings', {})
2880
  orders = env_data.get('orders', [])
2881
+
2882
+ req_lang = request.args.get('lang')
2883
+ if req_lang and req_lang in LANGUAGES:
2884
+ session[f'lang_{env_id}'] = req_lang
2885
+ lang = session.get(f'lang_{env_id}', settings.get('site_language', 'pl'))
2886
 
2887
  order = next((o for o in orders if o.get('id') == order_id), None)
2888
  if not order:
 
2924
  def admin(env_id):
2925
  data = get_env_data(env_id)
2926
  settings = data.get('settings', {})
2927
+
2928
+ req_lang = request.args.get('lang')
2929
+ if req_lang and req_lang in LANGUAGES:
2930
+ session[f'lang_{env_id}'] = req_lang
2931
+ lang = session.get(f'lang_{env_id}', settings.get('site_language', 'pl'))
2932
 
2933
  if settings.get('admin_password_enabled') and not session.get(f'admin_auth_{env_id}'):
2934
  return redirect(url_for('admin_login', env_id=env_id))
 
3163
  b_id = request.form.get('block_id')
3164
  block_to_del = next((b for b in blocks if b.get('id') == b_id), None)
3165
  if block_to_del:
3166
+ if block_to_del.get('type') == 'pdf' and block_to_del.get('url') and block_to_del.get('url').startswith('pdf_') and HF_TOKEN_WRITE:
3167
  try:
3168
  HfApi().delete_files(repo_id=REPO_ID, paths_in_repo=[f"pdfs/{block_to_del.get('url')}"], repo_type="dataset", token=HF_TOKEN_WRITE)
3169
  except Exception: pass
 
3353
  def admin_orders(env_id):
3354
  data = get_env_data(env_id)
3355
  settings = data.get('settings', {})
3356
+
3357
+ req_lang = request.args.get('lang')
3358
+ if req_lang and req_lang in LANGUAGES:
3359
+ session[f'lang_{env_id}'] = req_lang
3360
+ lang = session.get(f'lang_{env_id}', settings.get('site_language', 'pl'))
3361
 
3362
  if settings.get('admin_password_enabled') and not session.get(f'admin_auth_{env_id}'):
3363
  return redirect(url_for('admin_login', env_id=env_id))