nordabiz/templates/company/recommend.html
Maciej Pienczyn 6e00291a88 feat: AI usage user details + styled modals across app
- Add /admin/ai-usage/user/<id> route for detailed AI usage per user
- Add ai_usage_user.html template with stats, usage breakdown, logs
- Make user names clickable in AI usage dashboard ranking
- Replace all native browser dialogs (alert, confirm) with styled modals/toasts:
  - admin/fees.html, forum.html, recommendations.html, announcements.html, debug.html
  - calendar/admin.html, event.html
  - company_detail.html, company/recommend.html
  - forum/new_topic.html, topic.html
  - classifieds/view.html
  - auth/reset_password.html

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 10:30:35 +01:00

346 lines
10 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Polec firmę - {{ company.name }} - Norda Biznes Hub{% endblock %}
{% block extra_css %}
<style>
.recommend-container {
max-width: 800px;
margin: 0 auto;
}
.recommend-breadcrumb {
margin-bottom: var(--spacing-lg);
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
.recommend-breadcrumb a {
color: var(--primary);
text-decoration: none;
}
.recommend-breadcrumb a:hover {
text-decoration: underline;
}
.recommend-form {
background: var(--surface);
border-radius: var(--radius-xl);
padding: var(--spacing-2xl);
box-shadow: var(--shadow-lg);
}
.form-header {
margin-bottom: var(--spacing-xl);
}
.form-header h1 {
font-size: var(--font-size-2xl);
color: var(--text-primary);
margin-bottom: var(--spacing-sm);
}
.form-header p {
color: var(--text-secondary);
}
.company-info {
background: #f0f9ff;
border: 1px solid #bae6fd;
border-radius: var(--radius);
padding: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.company-info h3 {
font-size: var(--font-size-base);
font-weight: 600;
color: #0369a1;
margin-bottom: var(--spacing-sm);
}
.company-info p {
margin: 0;
color: #0c4a6e;
font-size: var(--font-size-sm);
}
.form-group {
margin-bottom: var(--spacing-lg);
}
.form-label {
display: block;
font-weight: 500;
margin-bottom: var(--spacing-sm);
color: var(--text-primary);
}
.form-label .required {
color: var(--error);
}
.form-input {
width: 100%;
padding: var(--spacing-md);
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: var(--font-size-base);
font-family: var(--font-family);
transition: var(--transition);
}
.form-input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
.form-textarea {
min-height: 200px;
resize: vertical;
}
.form-hint {
font-size: var(--font-size-sm);
color: var(--text-secondary);
margin-top: var(--spacing-xs);
}
.form-checkbox {
display: flex;
align-items: flex-start;
gap: var(--spacing-sm);
}
.form-checkbox input[type="checkbox"] {
margin-top: 4px;
width: 18px;
height: 18px;
cursor: pointer;
}
.form-checkbox label {
cursor: pointer;
font-weight: normal;
}
.form-actions {
display: flex;
gap: var(--spacing-md);
margin-top: var(--spacing-xl);
}
.guidelines {
background: #fef3c7;
border: 1px solid #fde68a;
border-radius: var(--radius);
padding: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.guidelines h3 {
font-size: var(--font-size-base);
font-weight: 600;
color: #92400e;
margin-bottom: var(--spacing-sm);
}
.guidelines ul {
margin: 0;
padding-left: var(--spacing-lg);
color: #78350f;
font-size: var(--font-size-sm);
}
.guidelines li {
margin-bottom: var(--spacing-xs);
}
.char-counter {
font-size: var(--font-size-sm);
color: var(--text-secondary);
text-align: right;
margin-top: var(--spacing-xs);
}
.char-counter.error {
color: var(--error);
}
@media (max-width: 768px) {
.recommend-form {
padding: var(--spacing-lg);
}
.form-actions {
flex-direction: column;
}
.form-actions .btn {
width: 100%;
}
}
</style>
{% endblock %}
{% block content %}
<div class="recommend-container">
<nav class="recommend-breadcrumb">
<a href="{{ url_for('index') }}">Katalog</a> &raquo;
<a href="{{ url_for('company_detail', company_id=company.id) }}">{{ company.name }}</a> &raquo;
Polec firmę
</nav>
<div class="recommend-form">
<div class="form-header">
<h1>Polec firmę</h1>
<p>Podziel się swoją opinią i pomóż innym członkom Norda Biznes</p>
</div>
<div class="company-info">
<h3>📋 Polecaną firmą</h3>
<p><strong>{{ company.name }}</strong></p>
<p>{{ company.description_short[:150] }}{% if company.description_short and company.description_short|length > 150 %}...{% endif %}</p>
</div>
<div class="guidelines">
<h3>💡 Wskazówki</h3>
<ul>
<li>Opisz swoje doświadczenia współpracy z firmą</li>
<li>Wspomnij konkretne usługi lub projekty</li>
<li>Bądź szczery i konstruktywny</li>
<li>Twoja rekomendacja będzie widoczna dla innych członków</li>
</ul>
</div>
<form method="POST" action="{{ url_for('company_recommend', slug=company.slug) }}" novalidate>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="form-group">
<label for="recommendation_text" class="form-label">
Rekomendacja <span class="required">*</span>
</label>
<textarea
id="recommendation_text"
name="recommendation_text"
class="form-input form-textarea"
placeholder="Opisz swoje doświadczenia z firmą, zrealizowane projekty, jakość współpracy..."
required
minlength="50"
maxlength="2000"
autofocus
></textarea>
<p class="form-hint">Minimum 50 znaków, maksimum 2000 znaków.</p>
<div class="char-counter" id="charCounter">0 / 2000 znaków</div>
</div>
<div class="form-group">
<label for="service_category" class="form-label">
Kategoria usługi (opcjonalnie)
</label>
<input
type="text"
id="service_category"
name="service_category"
class="form-input"
placeholder="np. Tworzenie stron WWW, Usługi prawne, Produkcja..."
maxlength="200"
>
<p class="form-hint">Jeśli polecanienie dotyczy konkretnej usługi, możesz ją tutaj wskazać.</p>
</div>
<div class="form-group">
<div class="form-checkbox">
<input
type="checkbox"
id="show_contact"
name="show_contact"
value="1"
checked
>
<label for="show_contact">
Udostępnij moje dane kontaktowe (email i telefon) innym członkom, aby mogli zadać pytania o szczegóły współpracy
</label>
</div>
<p class="form-hint" style="margin-left: 26px;">
Domyślnie zaznaczone. Transparentność wzmacnia zaufanie w sieci Norda Biznes.
</p>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary btn-lg">
Wyślij rekomendację
</button>
<a href="{{ url_for('company_detail', company_id=company.id) }}" class="btn btn-outline btn-lg">
Anuluj
</a>
</div>
</form>
</div>
</div>
<div id="toastContainer" style="position: fixed; top: 80px; right: 20px; z-index: 1100; display: flex; flex-direction: column; gap: 10px;"></div>
<style>
.toast { padding: 12px 20px; border-radius: var(--radius); background: var(--surface); border-left: 4px solid var(--primary); box-shadow: 0 4px 12px rgba(0,0,0,0.15); display: flex; align-items: center; gap: 10px; animation: toastIn 0.3s ease; }
.toast.success { border-left-color: var(--success); }
.toast.error { border-left-color: var(--error); }
.toast.warning { border-left-color: var(--warning); }
@keyframes toastIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes toastOut { from { opacity: 1; } to { opacity: 0; } }
</style>
{% endblock %}
{% block extra_js %}
function showToast(message, type = 'info', duration = 4000) {
const container = document.getElementById('toastContainer');
const icons = { success: '✓', error: '✕', warning: '⚠', info: '' };
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.innerHTML = `<span style="font-size:1.2em">${icons[type]||''}</span><span>${message}</span>`;
container.appendChild(toast);
setTimeout(() => { toast.style.animation = 'toastOut 0.3s ease forwards'; setTimeout(() => toast.remove(), 300); }, duration);
}
// Character counter
const textarea = document.getElementById('recommendation_text');
const counter = document.getElementById('charCounter');
textarea.addEventListener('input', function() {
const length = this.value.length;
counter.textContent = `${length} / 2000 znaków`;
if (length < 50) {
counter.classList.add('error');
counter.textContent = `${length} / 2000 znaków (minimum 50)`;
} else if (length > 2000) {
counter.classList.add('error');
} else {
counter.classList.remove('error');
}
});
// Client-side validation
document.querySelector('form').addEventListener('submit', function(e) {
const text = textarea.value.trim();
let valid = true;
if (text.length < 50) {
textarea.style.borderColor = 'var(--error)';
showToast('Rekomendacja musi mieć co najmniej 50 znaków.', 'error');
valid = false;
} else if (text.length > 2000) {
textarea.style.borderColor = 'var(--error)';
showToast('Rekomendacja może mieć maksymalnie 2000 znaków.', 'error');
valid = false;
} else {
textarea.style.borderColor = '';
}
if (!valid) {
e.preventDefault();
}
});
{% endblock %}