nodebb-plugin-niki-loyalty 1.2.6 → 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/library.js CHANGED
@@ -11,17 +11,17 @@ const Plugin = {};
11
11
  // ⚙️ AYARLAR & KURALLAR (GAME LOGIC)
12
12
  // =========================
13
13
  const SETTINGS = {
14
- dailyCap: 35, // Günlük Maksimum Puan
14
+ dailyCap: 35, // Günlük Maksimum Limit (Ne kadar kazanırsa kazansın buradan fazla alamaz)
15
15
  };
16
16
 
17
- // Puan Tablosu ve Limitleri
17
+ // Puan Tablosu ve Limitleri (Toplam Potansiyel ~45 Puan)
18
18
  const ACTIONS = {
19
- login: { points: 2, limit: 1, name: 'Günlük Giriş 👋' },
20
- new_topic: { points: 7, limit: 1, name: 'Yeni Konu 📝' },
21
- reply: { points: 3.5, limit: 2, name: 'Yorum Yazma 💬' },
22
- read: { points: 1, limit: 8, name: 'Konu Okuma 👀' }, // Heartbeat ile çalışır
23
- like_given: { points: 4, limit: 2, name: 'Beğeni Atma ❤️' }, // 4 puan x 2 = max 8
24
- like_taken: { points: 5, limit: 2, name: 'Beğeni Alma 🌟' } // 5 puan x 2 = max 10
19
+ login: { points: 5, limit: 1, name: 'Günlük Giriş 👋' }, // 5 Puan
20
+ new_topic: { points: 5, limit: 1, name: 'Yeni Konu 📝' }, // 5 Puan
21
+ reply: { points: 5, limit: 2, name: 'Yorum Yazma 💬' }, // 5 x 2 = 10 Puan
22
+ read: { points: 1, limit: 10, name: 'Konu Okuma 👀' }, // 1 x 10 = 10 Puan
23
+ like_given: { points: 2.5, limit: 2, name: 'Beğeni Atma ❤️' }, // 2.5 x 2 = 5 Puan
24
+ like_taken: { points: 5, limit: 2, name: 'Beğeni Alma 🌟' } // 5 x 2 = 10 Puan
25
25
  };
26
26
 
27
27
  // Ödüller
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-niki-loyalty",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "Niki The Cat Coffee Loyalty System - Earn points while studying on IEU Forum.",
5
5
  "main": "library.js",
6
6
  "nbbpm": {
@@ -14,19 +14,39 @@ $(document).ready(function () {
14
14
  }
15
15
 
16
16
  // -------------------------------------------------------------
17
- // 🔔 NİKİ TOAST BİLDİRİM FONKSİYONU (Sol Alt - Logo ile)
17
+ // 🔔 NİKİ TOAST BİLDİRİM FONKSİYONU (Sol Alt - Inline Stiller)
18
18
  // -------------------------------------------------------------
19
19
  function showNikiToast(message) {
20
20
  // Mevcut toast'ı kaldır
21
21
  $('.niki-toast').remove();
22
22
 
23
23
  // Logo yolunu al (plugin'in static klasöründen)
24
- const logoUrl = config.relative_path + '/plugins/nodebb-plugin-niki-loyalty/static/logo.png';
24
+ const logoUrl = (config && config.relative_path ? config.relative_path : '') + '/plugins/nodebb-plugin-niki-loyalty/static/logo.png';
25
25
 
26
- // Toast HTML'i oluştur
26
+ // Toast HTML'i oluştur (Inline stiller ile)
27
27
  const toastHtml = `
28
- <div class="niki-toast">
29
- <img src="${logoUrl}" alt="Niki" style="width: 28px; height: 28px; border-radius: 50%; object-fit: cover;">
28
+ <div class="niki-toast" style="
29
+ position: fixed;
30
+ bottom: 90px;
31
+ left: 25px;
32
+ background: linear-gradient(135deg, #4E342E 0%, #3E2723 100%);
33
+ color: #fff;
34
+ padding: 12px 20px;
35
+ border-radius: 16px;
36
+ font-size: 14px;
37
+ font-weight: 600;
38
+ box-shadow: 0 8px 25px rgba(0,0,0,0.3);
39
+ display: flex;
40
+ align-items: center;
41
+ gap: 12px;
42
+ z-index: 9999;
43
+ opacity: 0;
44
+ transform: translateY(20px) scale(0.9);
45
+ transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
46
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
47
+ border: 1px solid rgba(255,255,255,0.1);
48
+ ">
49
+ <img src="${logoUrl}" alt="Niki" style="width: 32px; height: 32px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.2);">
30
50
  <span>${message}</span>
31
51
  </div>
32
52
  `;
@@ -34,24 +54,35 @@ $(document).ready(function () {
34
54
  // Body'ye ekle
35
55
  $('body').append(toastHtml);
36
56
 
37
- // Animasyon için kısa gecikme
57
+ // Animasyon için kısa gecikme - görünür yap
38
58
  setTimeout(function () {
39
- $('.niki-toast').addClass('show');
59
+ $('.niki-toast').css({
60
+ 'opacity': '1',
61
+ 'transform': 'translateY(0) scale(1)'
62
+ });
40
63
  }, 50);
41
64
 
42
65
  // 4 saniye sonra kaldır
43
66
  setTimeout(function () {
44
- $('.niki-toast').removeClass('show');
67
+ $('.niki-toast').css({
68
+ 'opacity': '0',
69
+ 'transform': 'translateY(20px) scale(0.9)'
70
+ });
45
71
  setTimeout(function () {
46
72
  $('.niki-toast').remove();
47
- }, 300);
73
+ }, 400);
48
74
  }, 4000);
49
75
 
50
76
  // Widget'ı da bounce animasyonu ile canlandır
51
- $('#niki-floating-widget .niki-widget-content').addClass('niki-bounce');
52
- setTimeout(function () {
53
- $('#niki-floating-widget .niki-widget-content').removeClass('niki-bounce');
54
- }, 500);
77
+ const $widget = $('#niki-floating-widget .niki-widget-content');
78
+ if ($widget.length) {
79
+ $widget.css('transform', 'scale(1.1)');
80
+ setTimeout(function () {
81
+ $widget.css('transform', 'scale(1)');
82
+ }, 300);
83
+ }
84
+
85
+ console.log('[Niki-Loyalty] Toast gösterildi:', message);
55
86
  }
56
87
 
57
88
  // Fonksiyonu global yap (Konsoldan test için)
@@ -195,8 +226,9 @@ $(document).ready(function () {
195
226
 
196
227
  // 30 Saniyede bir tetikle (Günde 8 limit var backendde)
197
228
  heartbeatInterval = setInterval(function () {
198
- // Tarayıcı sekmesi aktif değilse gönderme (opsiyonel optimizasyon)
199
- if (document.hidden) return;
229
+ if (document.hidden) return; // Sekme aktif değilse sayma
230
+
231
+ console.log('[Niki-Loyalty] 10dk doldu. Puan isteniyor...');
200
232
 
201
233
  $.post('/api/niki-loyalty/heartbeat', {}, function (response) {
202
234
  if (response && response.earned) {
@@ -205,9 +237,13 @@ $(document).ready(function () {
205
237
  showNikiToast('Konu okuduğun için <strong style="color:#ffd700">+1 Puan</strong> kazandın! 🐈');
206
238
  }
207
239
  console.log('[Niki-Loyalty] Heartbeat başarılı. Yeni Puan:', response.total);
240
+ // Widget'ı hemen güncelle
241
+ updateSidebarWidget();
242
+ } else {
243
+ console.log('[Niki-Loyalty] Puan gelmedi (Günlük okuma limiti dolmuş olabilir).');
208
244
  }
209
245
  });
210
- }, 30000); // 30.000 ms = 30 Saniye
246
+ }, 600000); // 10 Dakika = 600.000 ms
211
247
  }
212
248
 
213
249
  // ============================================================
@@ -451,4 +487,105 @@ $(document).ready(function () {
451
487
  });
452
488
  });
453
489
  }
490
+ // -------------------------------------------------------------
491
+ // 📢 DUYURU SİSTEMİ (Marquee + Günlük Limit + Kapat Butonu)
492
+ // -------------------------------------------------------------
493
+ try {
494
+ const TARGET_CATEGORY_ID = 1; // Duyuruların çekileceği kategori ID
495
+ const MAX_DAILY_SHOW = 5; // Günde en fazla kaç kere gösterilecek
496
+
497
+ function checkAnnouncements() {
498
+ // Widget elementlerini bul veya oluştur
499
+ let $widget = $('.niki-marquee-widget');
500
+ if ($widget.length === 0) {
501
+ // Henüz yoksa oluştur (Başlangıçta gizli)
502
+ const widgetHtml = `
503
+ <div class="niki-marquee-widget" style="display:none;">
504
+ <div class="nm-content">
505
+ <div class="nm-icon">📢</div>
506
+ <div class="nm-text-container">
507
+ <span class="nm-text" id="niki-marquee-text">Duyuru Yükleniyor...</span>
508
+ </div>
509
+ <button class="nm-close" id="niki-marquee-close" title="Kapat">✖</button>
510
+ </div>
511
+ </div>
512
+ <style>
513
+ .niki-marquee-widget {
514
+ position: fixed; bottom: 85px; right: 20px; z-index: 9999;
515
+ background: #1a1a1a; border: 1px solid #C5A065; border-radius: 50px;
516
+ box-shadow: 0 5px 20px rgba(0,0,0,0.4); padding: 5px 15px;
517
+ width: 320px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
518
+ animation: slideInUp 0.5s ease-out;
519
+ }
520
+ .nm-content { display: flex; align-items: center; justify-content: space-between; height: 36px; }
521
+ .nm-icon { font-size: 18px; margin-right: 10px; animation: pulse 2s infinite; }
522
+ .nm-text-container { flex: 1; overflow: hidden; white-space: nowrap; position: relative; mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); }
523
+ .nm-text {
524
+ display: inline-block; color: #fff; font-size: 13px; font-weight: 500;
525
+ padding-left: 100%; animation: marquee 10s linear infinite;
526
+ }
527
+ .nm-close {
528
+ background: none; border: none; color: #888; cursor: pointer; font-size: 14px;
529
+ margin-left: 10px; padding: 0 5px; transition: 0.2s;
530
+ }
531
+ .nm-close:hover { color: #ff5252; transform: scale(1.1); }
532
+ @keyframes marquee { 0% { transform: translate(0, 0); } 100% { transform: translate(-100%, 0); } }
533
+ @keyframes slideInUp { from { transform: translateY(100px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
534
+ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } }
535
+ </style>
536
+ `;
537
+ $('body').append(widgetHtml);
538
+ $widget = $('.niki-marquee-widget');
539
+
540
+ // Kapatma butonu olayı
541
+ $('#niki-marquee-close').on('click', function () {
542
+ $widget.fadeOut();
543
+ sessionStorage.setItem('niki_session_closed', 'true'); // Bu oturumda bir daha açma
544
+ });
545
+ }
546
+
547
+ // Eğer bu oturumda kullanıcı kapattıysa gösterme
548
+ if (sessionStorage.getItem('niki_session_closed') === 'true') return;
549
+
550
+ // Günlük limit kontrolü
551
+ const today = new Date().toISOString().slice(0, 10);
552
+ const storageKey = 'niki_announce_count_' + today;
553
+ let count = parseInt(localStorage.getItem(storageKey) || '0');
554
+
555
+ if (count >= MAX_DAILY_SHOW) return; // Limit dolmuş
556
+
557
+ // API'den son konuyu çek
558
+ $.getJSON('/api/category/' + TARGET_CATEGORY_ID, function (data) {
559
+ if (data && data.topics && data.topics.length > 0) {
560
+ const topic = data.topics[0]; // En son konu
561
+ const lastTid = localStorage.getItem('niki_last_seen_tid');
562
+
563
+ // Yeni konu varsa veya henüz limit dolmadıysa göster
564
+ // (Kullanıcı "sürekli akmasını istiyorum" dediği için her sayfa yenilemede göstereceğiz, limite kadar)
565
+ const text = topic.title;
566
+ const url = config.relative_path + '/topic/' + topic.slug;
567
+
568
+ $('#niki-marquee-text').html(`<a href="${url}" style="color:#fff;text-decoration:none;">${text}</a>`);
569
+ $widget.fadeIn();
570
+
571
+ // Sayacı artır (Sadece görünür olduğunda)
572
+ if ($widget.is(':visible')) {
573
+ localStorage.setItem(storageKey, count + 1);
574
+ // Yeni konuyu gördü olarak işaretle
575
+ localStorage.setItem('niki_last_seen_tid', topic.tid);
576
+ }
577
+ }
578
+ });
579
+ }
580
+
581
+ // Başlat (Sayfa yüklendikten biraz sonra)
582
+ setTimeout(checkAnnouncements, 2000);
583
+
584
+ // Sayfa geçişlerinde de kontrol et
585
+ $(window).on('action:ajaxify.end', function () {
586
+ setTimeout(checkAnnouncements, 2000);
587
+ });
588
+
589
+ } catch (e) { console.warn("[Niki] Duyuru hatası:", e); }
590
+
454
591
  });
File without changes