Sugester V2

Widget głosowania - osadzanie na zewnętrznych stronach

Aktualizacja: Wyświetleń: 22

Czym jest widget głosowania?

Widget głosowania pozwala zbierać opinie użytkowników bezpośrednio na stronach marketingowych lub w aplikacjach zewnętrznych. Użytkownicy mogą głosować czy dana funkcja jest dla nich przydatna, a ich głosy trafiają do Forum Sugestii.

Jak to wygląda?

Przed głosowaniem

Po głosowaniu

Funkcje widgetu

  • Głosowanie - przyciski “Tak” / “Nie”
  • Licznik głosów - po zagłosowaniu pokazuje ile osób głosowało
  • Komentarze - możliwość dodania opinii tekstowej
  • Link do dyskusji - przekierowanie do pełnego wątku na forum

Prompt dla LLM (Claude, ChatGPT, itp.)

Jeśli używasz LLM do kodowania strony, możesz użyć tego promptu:

Dodaj widget głosowania do mojej strony. Widget powinien:

1. Wyświetlać pytanie "Przydatna funkcja?" z przyciskami "Tak" / "Nie"
2. Po głosowaniu pokazać liczbę głosów i link do dyskusji
3. Wysyłać głos na endpoint: POST {FORUM_URL}/rate?helpful=yes|no
4. Pobierać dane z: GET {FORUM_URL}.json (zwraca rating, comments_count)

Gdzie {FORUM_URL} to ścieżka do wpisu w Forum Sugestii, np.:
/forum/sugestie/nazwa-funkcji-ABC123

Widget powinien być:
- Kompaktowy (max 280px szerokości)
- W ciemnym motywie (slate/purple) lub dopasowany do strony
- Responsywny (fixed na mobile, float-right na desktop)

Mapowanie stron na wpisy forum:
- /funkcje/moja-funkcja → /forum/sugestie/moja-funkcja-TOKEN

Gdzie to działa?

Środowisko Działa? Uwagi
Strony w CMS Sugester/Intum ✅ Tak Pełna integracja
Aplikacje NOE ✅ Tak Pełna integracja
Zewnętrzne strony (własny hosting) ✅ Tak Wymaga CORS lub proxy
Inne CMS-y (WordPress, itp.) ⚠️ Częściowo Backend musi być Sugester

Wymagania backendu:

  • Forum Sugestii w Sugester/Intum
  • Endpoint /rate z wyłączonym CSRF (skip_forgery_protection)
  • Endpoint .json zwracający rating i comments_count

Kod do osadzenia

Aby osadzić widget na swojej stronie, dodaj poniższy kod HTML i JavaScript:

1. HTML widgetu

<!-- Widget głosowania -->
<div id="voting-widget" class="hidden">
  <div class="voting-box">
    <p class="voting-question">Przydatna funkcja?</p>
    <div id="vote-buttons" class="voting-buttons">
      <button onclick="vote('yes')" class="voting-btn btn-yes">👍 Tak</button>
      <button onclick="vote('no')" class="voting-btn btn-no">👎 Nie</button>
    </div>
    <p id="vote-result" class="hidden"></p>
    <div id="forum-link" class="hidden">
      <a id="forum-link-href" href="#" target="_blank">
        💬 Dyskusja <span id="comment-count"></span>
      </a>
    </div>
  </div>
</div>

2. JavaScript

(function() {
  // Konfiguracja - zmień na swoje wartości
  const FORUM_BASE = 'https://twoja-domena.pl/forum/sugestie';
  
  const entryMap = {
    '/funkcje/moja-funkcja': { 
      path: FORUM_BASE + '/moja-funkcja-ABC123', 
      id: 123 
    },
    // dodaj więcej mapowań...
  };

  const path = window.location.pathname.replace(/\/$/, '');
  const entry = entryMap[path];
  
  if (entry) {
    document.getElementById('voting-widget').classList.remove('hidden');
    window.currentEntry = entry;

    // Link do forum
    document.getElementById('forum-link-href').href = entry.path;
    document.getElementById('forum-link').classList.remove('hidden');

    // Pobierz liczbę komentarzy
    fetch(entry.path + '.json')
      .then(r => r.json())
      .then(data => {
        if (data.comments_count > 0) {
          document.getElementById('comment-count').textContent = 
            '(' + data.comments_count + ')';
        }
      })
      .catch(() => {});
  }

  window.vote = async function(helpful) {
    const btns = document.querySelectorAll('.voting-btn');
    btns.forEach(b => b.disabled = true);

    try {
      await fetch(window.currentEntry.path + '/rate?helpful=' + helpful, 
        { method: 'POST' });
      
      // Pobierz aktualny rating
      const data = await fetch(window.currentEntry.path + '.json')
        .then(r => r.json());
      const rating = data?.rating || 0;
      
      let msg = '✓ Dziękujemy!';
      if (rating > 0) {
        msg = helpful === 'yes' 
          ? '✓ ' + rating + ' osób chce tę funkcję'
          : '✓ Dziękujemy! (głosów: ' + rating + ')';
      }
      
      document.getElementById('vote-result').textContent = msg;
      document.getElementById('vote-result').classList.remove('hidden');
      document.getElementById('vote-buttons').style.opacity = '0.5';
    } catch(e) {
      document.getElementById('vote-result').textContent = 'Błąd - spróbuj ponownie';
      document.getElementById('vote-result').classList.remove('hidden');
      btns.forEach(b => b.disabled = false);
    }
  };
})();

3. Style CSS

.voting-box {
  padding: 1rem;
  background: rgba(30, 41, 59, 0.9);
  border-radius: 0.75rem;
  border: 1px solid rgba(168, 85, 247, 0.3);
  max-width: 280px;
}
.voting-question {
  color: #cbd5e1;
  font-size: 0.875rem;
  margin-bottom: 0.75rem;
}
.voting-buttons {
  display: flex;
  gap: 0.5rem;
}
.voting-btn {
  flex: 1;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 500;
  border-radius: 0.5rem;
  border: none;
  cursor: pointer;
  white-space: nowrap;
}
.btn-yes { background: #059669; color: white; }
.btn-yes:hover { background: #10b981; }
.btn-no { background: #475569; color: white; }
.btn-no:hover { background: #64748b; }
#vote-result { 
  color: #10b981; 
  font-size: 0.875rem; 
  margin-top: 0.75rem; 
}
#forum-link a {
  color: #a78bfa;
  font-size: 0.75rem;
}
.hidden { display: none; }

Wymagania techniczne

  • Wpis w Forum Sugestii z włączonym publicznym dostępem
  • Endpoint /rate z wyłączoną ochroną CSRF (skip_forgery_protection)
  • Endpoint .json zwracający comments_count i rating
  • CORS skonfigurowany jeśli widget na innej domenie

Czy ten wpis był pomocny?

Customer Reviews

Brak komentarzy

Dodaj komentarz