Sync: Current production state

- Added CompanyRecommendation system
- Made company pages public (removed @login_required)
- CSS refactor: inline styles instead of external fluent CSS
- Added release notes page
- Added admin recommendations panel
- Company logos (webp format)
- Docker compose configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-01-08 12:26:22 +01:00
parent 055d9c1cfa
commit 6e4e7c2240
135 changed files with 7865 additions and 1793 deletions

View File

@ -1,41 +0,0 @@
# Build Progress: Admin Rights for Artur Wiertel
## Status: READY FOR DEPLOYMENT
### Completed Tasks
- [x] **subtask-1-1**: Created migration script `grant_admin_artur_wiertel.py`
- Script finds user by company_id=12 (WATERM)
- Sets is_admin=True
- Supports --dry-run for verification
- Safe rollback on errors
### Deployment Instructions
1. SSH to production server:
```bash
ssh maciejpi@10.22.68.249
```
2. Copy script to production:
```bash
scp grant_admin_artur_wiertel.py maciejpi@10.22.68.249:/var/www/nordabiznes/
```
3. Run script (dry-run first):
```bash
cd /var/www/nordabiznes
sudo -u www-data ./venv/bin/python3 grant_admin_artur_wiertel.py --dry-run
```
4. If dry-run looks correct, execute:
```bash
sudo -u www-data ./venv/bin/python3 grant_admin_artur_wiertel.py
```
### Manual Verification
After running the script:
1. Ask Artur Wiertel to log in at https://nordabiznes.pl/login
2. Verify he can access /admin/news panel
3. Verify he can moderate news items

View File

@ -1,41 +0,0 @@
{
"feature": "admin-rights-artur-wiertel",
"workflow_type": "simple",
"total_phases": 1,
"recommended_workers": 1,
"phases": [
{
"phase": 1,
"name": "Grant Admin Privileges",
"description": "Set is_admin=True for Artur Wiertel's user account",
"depends_on": [],
"subtasks": [
{
"id": "subtask-1-1",
"description": "Update user record to set is_admin=True for Artur Wiertel (WATERM owner, company_id=12)",
"service": "database",
"status": "completed",
"files_to_create": [],
"files_to_modify": [],
"database_changes": [
"UPDATE users SET is_admin = TRUE WHERE company_id = 12"
],
"patterns_from": [],
"verification": {
"type": "manual",
"run": "Login as Artur Wiertel and verify access to /admin/news"
},
"notes": "Created grant_admin_artur_wiertel.py script that safely updates is_admin=True for WATERM owner (company_id=12). Script supports --dry-run mode and includes error handling.",
"updated_at": "2026-01-06T20:58:16.509339+00:00"
}
]
}
],
"metadata": {
"created_at": "2026-01-06",
"complexity": "simple",
"estimated_sessions": 1,
"notes": "Database-only change, no code modifications needed"
},
"last_updated": "2026-01-06T20:58:16.509348+00:00"
}

4
.gitignore vendored
View File

@ -65,3 +65,7 @@ preflight_report_*.txt
venv-py312/
.claude_settings.json
.worktrees/
*.dump
*.sql
nordabiz_*.dump
nordabiz_*.sql

View File

@ -129,11 +129,20 @@ curl -I https://nordabiznes.pl/health
- Baza: `nordabiz`, użytkownik aplikacji: `nordabiz_app`
### Testowanie na produkcji
- **ZAWSZE używaj konta testowego** do weryfikacji funkcjonalności
- **Konto testowe:** test@nordabiznes.pl / TestNorda2024!
- Konto ma uprawnienia zwykłego użytkownika (nie admin)
- **ZAWSZE używaj kont testowych** do weryfikacji funkcjonalności
- Używaj przeglądarki (browser automation) do testów wymagających logowania
**Konta testowe (PROD):**
| Konto | Email | Hasło | Rola |
|-------|-------|-------|------|
| Test User | `test@nordabiznes.pl` | `&Rc2LdbSw&jiGR0ek@Bz` | Zwykły użytkownik |
| Test Admin | `testadmin@nordabiznes.pl` | `cSfQbbwegwv1v3Q2Dm0Q` | Administrator |
**Użycie:**
- **Test User** - do testowania funkcji dostępnych dla zwykłych użytkowników
- **Test Admin** - do testowania panelu admina (rekomendacje, składki, kalendarz, forum, news)
## Skrypty danych
### Import (wykonywać kolejno)

1450
app.py

File diff suppressed because it is too large Load Diff

View File

@ -450,7 +450,6 @@ class CompanyWebsiteAnalysis(Base):
hosting_ip = Column(String(45))
server_software = Column(String(100))
site_author = Column(String(255)) # Website creator/agency
copyright_year = Column(Integer) # Year from copyright notice (e.g., © 2015)
site_generator = Column(String(100))
domain_registrar = Column(String(100))
is_mobile_friendly = Column(Boolean, default=False)
@ -990,6 +989,41 @@ class CompanySocialMedia(Base):
)
class CompanyRecommendation(Base):
"""Peer recommendations between NORDA BIZNES members"""
__tablename__ = 'company_recommendations'
id = Column(Integer, primary_key=True)
company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)
user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False, index=True)
# Recommendation content
recommendation_text = Column(Text, nullable=False)
service_category = Column(String(200)) # Optional: specific service recommended for
# Privacy settings
show_contact = Column(Boolean, default=True) # Show recommender's contact info
# Moderation
status = Column(String(20), default='pending', index=True) # pending, approved, rejected
moderated_by = Column(Integer, ForeignKey('users.id'), nullable=True)
moderated_at = Column(DateTime)
rejection_reason = Column(Text)
# Timestamps
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
# Relationships
company = relationship('Company', backref='recommendations')
user = relationship('User', foreign_keys=[user_id], backref='recommendations_given')
moderator = relationship('User', foreign_keys=[moderated_by], backref='recommendations_moderated')
__table_args__ = (
UniqueConstraint('user_id', 'company_id', name='uq_user_company_recommendation'),
)
class UserNotification(Base):
"""
In-app notifications for users.
@ -1112,53 +1146,6 @@ class MembershipFeeConfig(Base):
company = relationship('Company')
# ============================================================
# ANNOUNCEMENTS
# ============================================================
class Announcement(Base):
"""
Board announcements visible to logged-in members.
Used for organizational communications.
"""
__tablename__ = 'announcements'
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
content = Column(Text, nullable=False)
# Types: general, fees, event, important, urgent
announcement_type = Column(String(50), default='general')
is_published = Column(Boolean, default=False)
is_pinned = Column(Boolean, default=False)
publish_date = Column(DateTime)
expire_date = Column(DateTime)
# Target audience: all, fee_pending, fee_overdue
target_audience = Column(String(50), default='all')
author_id = Column(Integer, ForeignKey('users.id'), nullable=False)
created_at = Column(DateTime, default=datetime.now)
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
# Relationships
author = relationship('User', backref='announcements')
@property
def is_visible(self):
now = datetime.now()
if not self.is_published:
return False
if self.publish_date and now < self.publish_date:
return False
if self.expire_date and now > self.expire_date:
return False
return True
# ============================================================
# DATABASE INITIALIZATION
# ============================================================

17
docker-compose.yml Normal file
View File

@ -0,0 +1,17 @@
version: '3.8'
services:
postgres:
image: postgres:15
container_name: nordabiz-postgres
environment:
POSTGRES_DB: nordabiz
POSTGRES_USER: nordabiz_app
POSTGRES_PASSWORD: dev_password
ports:
- "5433:5432" # Port 5433 lokalnie (unika kolizji z innymi projektami)
volumes:
- nordabiz_pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
nordabiz_pgdata:

View File

@ -1,98 +0,0 @@
#!/usr/bin/env python3
"""
Grant admin rights to Artur Wiertel (WATERM owner, company_id=12)
This script updates the is_admin field to True for the user associated
with WATERM company.
Usage:
python grant_admin_artur_wiertel.py [--dry-run]
Options:
--dry-run Show what would be changed without making changes
"""
import sys
from database import SessionLocal, User, Company
def grant_admin_to_waterm_owner(dry_run=False):
"""Grant admin rights to WATERM owner (company_id=12)"""
session = SessionLocal()
try:
# First, verify the company exists
company = session.query(Company).filter(Company.id == 12).first()
if not company:
print("❌ Error: Company with id=12 not found")
return False
print(f"✅ Found company: {company.name} (NIP: {company.nip})")
# Find the user associated with this company
user = session.query(User).filter(User.company_id == 12).first()
if not user:
print(f"❌ Error: No user found for company_id=12 ({company.name})")
print(" Please ensure the user account exists before granting admin rights.")
return False
print(f"✅ Found user: {user.name} ({user.email})")
print(f" Current admin status: {user.is_admin}")
if user.is_admin:
print(" User already has admin rights. No changes needed.")
return True
if dry_run:
print("\n[DRY RUN] Would set is_admin=True for this user")
print("[DRY RUN] No changes made to database")
return True
# Grant admin rights
user.is_admin = True
session.commit()
print(f"\n✅ Successfully granted admin rights to {user.name}")
print(f" Email: {user.email}")
print(f" Company: {company.name}")
print(f" Admin status: {user.is_admin}")
return True
except Exception as e:
session.rollback()
print(f"❌ Error: {e}")
return False
finally:
session.close()
def main():
dry_run = '--dry-run' in sys.argv
print("=" * 60)
print("Grant Admin Rights - Artur Wiertel (WATERM)")
print("=" * 60)
if dry_run:
print("\n🔍 DRY RUN MODE - No changes will be made\n")
success = grant_admin_to_waterm_owner(dry_run=dry_run)
if success:
print("\n✅ Operation completed successfully")
if not dry_run:
print("\nNext steps:")
print("1. Ask Artur to log in at https://nordabiznes.pl/login")
print("2. Verify access to /admin/news panel")
return 0
else:
print("\n❌ Operation failed")
return 1
if __name__ == '__main__':
sys.exit(main())

View File

@ -7,12 +7,12 @@ Flask-Login==0.6.3
Werkzeug==3.0.1
# Security
Flask-WTF==1.2.2
Flask-WTF==1.2.1
Flask-Limiter==3.5.0
# Database
SQLAlchemy==2.0.23
psycopg2-binary==2.9.11
psycopg2-binary==2.9.9
# Google Gemini AI
google-generativeai==0.3.2
@ -21,8 +21,8 @@ google-generativeai==0.3.2
python-dotenv==1.0.0
# Email (for verification)
Flask-Mail==0.10.0
Flask-Mail==0.9.1
# Utilities
requests==2.32.5
requests==2.31.0
feedparser==6.0.10

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,21 @@
<svg width="177" height="37" viewBox="0 0 177 37" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_65_87)">
<path d="M60.7128 21.1835C60.7128 19.4487 61.0111 17.8495 61.6212 16.3722C62.2313 14.8949 63.0584 13.6344 64.1159 12.5908C65.1734 11.5473 66.3936 10.7205 67.8172 10.1242C69.2408 9.52784 70.7322 9.22968 72.3456 9.22968C73.959 9.22968 75.464 9.52784 76.874 10.1242C78.284 10.7205 79.5178 11.5473 80.5889 12.5908C81.66 13.6344 82.487 14.8949 83.0971 16.3722C83.7072 17.8495 84.0055 19.4623 84.0055 21.1835C84.0055 22.9048 83.7072 24.5582 83.0971 26.022C82.487 27.4857 81.6464 28.7462 80.5889 29.8033C79.5178 30.8604 78.284 31.6872 76.874 32.27C75.464 32.8528 73.959 33.1374 72.3456 33.1374C70.7322 33.1374 69.2273 32.8392 67.8172 32.27C66.4072 31.6872 65.1734 30.8604 64.1159 29.8033C63.0584 28.7462 62.2313 27.4857 61.6212 26.022C61.0111 24.5582 60.7128 22.9454 60.7128 21.1835ZM66.0682 21.1835C66.0682 22.2542 66.2309 23.23 66.5699 24.0974C66.8953 24.9648 67.3563 25.7103 67.9121 26.3337C68.4816 26.9571 69.1459 27.4451 69.9052 27.7839C70.6644 28.1227 71.4779 28.2989 72.3321 28.2989C73.1862 28.2989 73.9997 28.1227 74.7589 27.7839C75.5182 27.4451 76.1961 26.9571 76.7655 26.3337C77.3485 25.7103 77.8095 24.9648 78.1349 24.0974C78.4603 23.23 78.6365 22.2542 78.6365 21.1835C78.6365 20.1128 78.4738 19.1777 78.1349 18.2967C77.7959 17.4158 77.3485 16.6568 76.7655 16.0333C76.1825 15.4099 75.5182 14.922 74.7589 14.5832C73.9997 14.2443 73.1862 14.0681 72.3321 14.0681C71.4779 14.0681 70.6644 14.2443 69.9052 14.5832C69.1459 14.922 68.4816 15.4099 67.9121 16.0333C67.3427 16.6568 66.8953 17.4158 66.5699 18.2967C66.2445 19.1777 66.0682 20.1399 66.0682 21.1835Z" fill="#022563" stroke="#022563" stroke-width="0.7"/>
<path d="M86.6222 11.6421C86.6222 10.3817 87.2188 9.75825 88.4254 9.75825H90.1337C91.3268 9.75825 91.9369 10.3817 91.9369 11.6421V13.0245C91.9369 13.1736 91.9369 13.3092 91.9098 13.4311C91.8963 13.5531 91.8827 13.6615 91.8827 13.7429C91.8556 13.8648 91.842 13.9733 91.842 14.0546H91.9234C92.1539 13.5802 92.4928 13.0517 92.9267 12.4824C93.3605 11.9132 93.9029 11.3982 94.5536 10.9103C95.1909 10.4359 95.9637 10.0293 96.8314 9.70404C97.7127 9.37876 98.716 9.21613 99.8548 9.21613C102.336 9.21613 104.261 9.90733 105.631 11.2762C106.986 12.6451 107.664 14.8678 107.664 17.9037V30.7249C107.664 31.9854 107.054 32.6088 105.82 32.6088H103.936C102.702 32.6088 102.092 31.9854 102.092 30.7249V19.0692C102.092 17.6597 101.861 16.5348 101.387 15.681C100.912 14.8271 99.9769 14.407 98.5804 14.407C97.5906 14.407 96.6958 14.5967 95.9094 14.9898C95.1231 15.3828 94.4452 15.9114 93.8893 16.6026C93.3334 17.2938 92.8996 18.0934 92.6013 19.0015C92.2895 19.9095 92.1403 20.8718 92.1403 21.8883V30.7114C92.1403 31.9718 91.5438 32.5952 90.3371 32.5952H88.4119C87.2188 32.5952 86.6086 31.9718 86.6086 30.7114V11.615L86.6222 11.6421Z" fill="#022563" stroke="#022563" stroke-width="0.7"/>
<path d="M111.271 30.5352C110.769 30.237 110.498 29.8711 110.43 29.4238C110.362 28.9766 110.498 28.5158 110.823 28.0143L111.352 27.2147C111.677 26.7403 112.03 26.4828 112.423 26.415C112.816 26.3608 113.291 26.4692 113.847 26.7674C114.375 27.0656 115.053 27.3909 115.88 27.7568C116.707 28.1227 117.697 28.3125 118.836 28.3125C119.799 28.3125 120.558 28.1092 121.114 27.689C121.67 27.2824 121.954 26.7132 121.954 26.0084C121.954 25.385 121.683 24.8971 121.141 24.5311C120.599 24.1652 119.907 23.8264 119.08 23.5147C118.24 23.2029 117.358 22.8777 116.409 22.5253C115.46 22.1729 114.565 21.7257 113.738 21.1971C112.911 20.6685 112.22 19.9909 111.677 19.1641C111.135 18.3374 110.864 17.2802 110.864 15.9791C110.864 14.8949 111.094 13.9191 111.542 13.0652C111.989 12.2114 112.613 11.5066 113.386 10.9374C114.159 10.3817 115.067 9.948 116.111 9.64983C117.155 9.35166 118.253 9.20258 119.419 9.20258C120.91 9.20258 122.171 9.39232 123.215 9.77181C124.259 10.1513 125.059 10.5037 125.656 10.8289C126.157 11.1 126.442 11.4524 126.537 11.8861C126.618 12.3333 126.551 12.7942 126.32 13.2956L125.886 14.0952C125.629 14.6238 125.29 14.9355 124.883 15.0304C124.476 15.1253 123.988 15.044 123.432 14.8136C122.931 14.5832 122.334 14.3392 121.629 14.0817C120.924 13.8377 120.111 13.7022 119.175 13.7022C118.24 13.7022 117.467 13.892 116.938 14.2714C116.409 14.6509 116.152 15.2066 116.152 15.9114C116.152 16.5348 116.423 17.0363 116.965 17.4158C117.507 17.7953 118.199 18.1341 119.026 18.4322C119.853 18.7304 120.748 19.0421 121.697 19.381C122.646 19.7198 123.541 20.1535 124.368 20.6821C125.195 21.2106 125.886 21.8883 126.429 22.715C126.971 23.5418 127.242 24.5854 127.242 25.8594C127.242 26.8623 127.039 27.7839 126.646 28.6242C126.252 29.4645 125.683 30.1963 124.937 30.8062C124.191 31.4161 123.297 31.9176 122.239 32.27C121.182 32.6224 120.016 32.7985 118.728 32.7985C116.911 32.7985 115.392 32.5275 114.145 31.9989C112.898 31.4703 111.949 30.9689 111.271 30.4945V30.5352Z" fill="#022563" stroke="#022563" stroke-width="0.7"/>
<path d="M130.008 11.6421C130.008 10.3817 130.618 9.75824 131.852 9.75824H133.736C134.97 9.75824 135.58 10.3817 135.58 11.6421V23.2978C135.58 24.7073 135.811 25.8322 136.285 26.6861C136.746 27.5399 137.668 27.9601 139.051 27.9601C140.041 27.9601 140.936 27.7568 141.722 27.3366C142.508 26.9165 143.173 26.3473 143.702 25.6289C144.23 24.9106 144.623 24.0839 144.908 23.1623C145.179 22.2407 145.329 21.2648 145.329 20.2483V11.6421C145.329 10.3817 145.939 9.75824 147.172 9.75824H149.057C150.291 9.75824 150.901 10.3817 150.901 11.6421V30.7385C150.901 31.9989 150.291 32.6223 149.057 32.6223H147.349C146.156 32.6223 145.545 31.9989 145.545 30.7385V28.9901C145.545 28.8681 145.559 28.7597 145.586 28.6784C145.586 28.5564 145.6 28.448 145.627 28.3667H145.545C145.288 28.963 144.908 29.5458 144.42 30.115C143.932 30.6842 143.363 31.1857 142.685 31.633C142.007 32.0802 141.261 32.4462 140.448 32.7308C139.634 33.0154 138.739 33.1509 137.777 33.1509C135.377 33.1509 133.479 32.4733 132.096 31.1315C130.713 29.7897 130.008 27.567 130.008 24.4498V11.6286V11.6421Z" fill="#022563" stroke="#022563" stroke-width="0.7"/>
<path d="M154.372 2.6835C154.372 1.42306 154.968 0.799622 156.175 0.799622H158.1C159.293 0.799622 159.903 1.42306 159.903 2.6835V25.0461C159.903 25.6154 159.957 26.0762 160.052 26.415C160.161 26.7538 160.296 27.0249 160.473 27.2282C160.649 27.4179 160.839 27.5535 161.042 27.6348C161.245 27.7161 161.449 27.7568 161.652 27.7974C162.059 27.8516 162.384 28.0143 162.642 28.2718C162.886 28.5293 163.022 28.9088 163.022 29.4102V30.9282C163.022 31.5245 162.886 31.9989 162.601 32.3377C162.317 32.6765 161.842 32.8527 161.178 32.8527C160.418 32.8527 159.646 32.785 158.859 32.6223C158.073 32.4597 157.341 32.148 156.663 31.633C155.985 31.1315 155.443 30.3861 155.022 29.4102C154.602 28.4344 154.385 27.1333 154.385 25.4934V2.6835H154.372Z" fill="#022563" stroke="#022563" stroke-width="0.7"/>
<path d="M165.991 14.922H164.811C163.618 14.922 163.008 14.2985 163.008 13.0381V12.2791C163.008 11.0187 163.618 10.3952 164.852 10.3952H166.127V5.73297C166.127 4.47253 166.737 3.84909 167.97 3.84909H169.719C170.953 3.84909 171.563 4.47253 171.563 5.73297V10.3952H174.804C176.037 10.3952 176.648 11.0187 176.648 12.2791V13.0381C176.648 14.2985 176.051 14.922 174.844 14.922H171.55V23.7993C171.55 24.6667 171.672 25.3579 171.902 25.8865C172.133 26.415 172.431 26.8216 172.784 27.1469C173.136 27.4722 173.516 27.689 173.95 27.8246C174.37 27.9601 174.777 28.0414 175.156 28.0685C175.834 28.1227 176.309 28.2989 176.58 28.5564C176.864 28.8275 177 29.2747 177 29.8982V31.2806C177 31.9718 176.81 32.4597 176.431 32.7308C176.051 33.0154 175.482 33.1509 174.722 33.1509C173.733 33.1509 172.716 33.0018 171.672 32.7037C170.628 32.4055 169.692 31.9311 168.865 31.267C168.025 30.6165 167.347 29.7491 166.804 28.6919C166.262 27.6348 165.991 26.3202 165.991 24.7751V14.922Z" fill="#022563" stroke="#022563" stroke-width="0.7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.76252 23.7586C1.39646 23.5824 0.623649 23.7451 0.515185 22.8099C0.474511 22.4304 2.94207 16.5755 3.28102 15.681C4.16229 13.3363 6.35869 2.68352 7.83652 0.921618C9.39569 -0.921606 12.1073 -0.0948658 11.3074 3.71356C10.8464 5.96338 7.2942 20.7769 7.3891 22.322C7.72805 22.0103 7.49757 22.2813 7.70094 21.8747L13.5309 10.2733C14.8053 7.75239 17.9915 8.17253 17.5712 12.4418C17.3678 14.5289 16.7577 17.9443 16.6899 19.6385C17.7068 17.9985 18.805 15.193 19.8218 13.4447C20.9471 11.5066 20.7573 12.6722 21.3674 10.3139C21.6521 9.18902 21.8284 7.90147 23.2927 7.49488C24.6349 7.12894 25.8551 7.95568 26.2212 9.40587C26.75 11.5608 24.6485 17.6191 25.6111 20.8582C26.6551 20.4245 26.75 20.2213 27.699 19.7604C29.448 18.9202 28.8379 19.1235 29.7056 18.7169C30.5733 18.3103 30.6818 18.2018 31.2919 17.9443C33.1222 17.1311 33.5968 16.1553 35.1288 16.9278C36.8778 17.8359 36.5253 20.411 33.895 20.926C32.7562 21.1293 31.8749 21.5495 30.7767 21.9154C30.0581 22.1729 29.6378 22.322 29.0006 22.6337C28.1329 23.0267 26.3161 24.0297 25.6246 24.6396C25.2315 24.9919 25.001 25.2359 24.5807 25.5205C22.0724 27.2011 18.466 24.6125 19.293 20.6007L19.8218 17.9037C19.7269 18.1341 19.5778 18.3509 19.4422 18.622C18.5474 20.5601 17.8017 22.1322 17.0424 24.2601C16.8933 24.6802 16.5137 25.5883 16.473 26.0084C16.4052 26.6861 17.0966 29.9659 14.5749 30.9011C11.6328 31.9854 9.72108 28.8004 10.3176 25.8729C10.7515 23.718 11.3887 20.7498 11.4701 18.622C11.1582 18.9879 9.7482 22.0103 9.54483 22.4575C8.97539 23.7586 8.3924 24.9784 7.83652 26.3337C7.28064 27.6755 6.76543 28.9766 6.25023 30.3725C5.92484 31.2264 6.01974 31.6736 5.92484 32.6088C5.85705 33.3813 5.69435 34.059 5.5181 34.8044C4.59615 38.4366 -0.284739 37.4608 0.0135379 32.5681C0.13556 30.5894 0.596533 29.5458 0.881251 28.1227C1.17953 26.659 1.46425 25.2224 1.74896 23.7586H1.76252Z" fill="url(#paint0_linear_65_87)"/>
<path d="M38.3828 31.2535V2.06007C38.3828 1.13846 39.1284 0.379486 40.0639 0.379486H42.64C43.5619 0.379486 44.3212 1.12491 44.3212 2.06007V31.2535C44.3212 32.1751 43.5755 32.9341 42.64 32.9341H40.0639C39.142 32.9341 38.3828 32.1886 38.3828 31.2535ZM41.718 20.6956L41.8943 17.9985C41.9485 17.1718 42.5857 16.5212 43.3992 16.4264C44.9313 16.2637 46.3006 15.8436 47.4937 15.1388C49.0394 14.2308 50.3138 13.0245 51.3307 11.493C52.3475 9.96154 53.0932 8.24029 53.5677 6.3293C53.9338 4.89267 54.1643 3.41538 54.2456 1.91099C54.2999 1.04359 55.0456 0.393039 55.9133 0.393039H58.5707C59.5604 0.393039 60.3061 1.23333 60.2383 2.22271C60.1027 4.45897 59.696 6.62747 59.0452 8.71465C58.2046 11.3711 56.9844 13.7429 55.371 15.83C53.7576 17.9172 51.8052 19.5571 49.4868 20.7634C47.6971 21.6985 45.7041 22.2678 43.5212 22.4846C42.4908 22.5795 41.6231 21.7256 41.6909 20.6956H41.718ZM54.0829 31.9311L48.8224 20.0722C48.4428 19.2183 48.836 18.2154 49.7037 17.8495L52.1848 16.7923C52.9983 16.4399 53.9474 16.7923 54.3405 17.6055L60.6586 30.5216C61.2009 31.633 60.3874 32.9341 59.1536 32.9341H55.615C54.9507 32.9341 54.3541 32.541 54.0829 31.9311Z" fill="#022563"/>
</g>
<defs>
<linearGradient id="paint0_linear_65_87" x1="25.245" y1="7.29158" x2="-1.53685" y2="31.6562" gradientUnits="userSpaceOnUse">
<stop stop-color="#00A182"/>
<stop offset="1" stop-color="#027751"/>
</linearGradient>
<clipPath id="clip0_65_87">
<rect width="177" height="37" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Warstwa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 566.9 283.5" style="enable-background:new 0 0 566.9 283.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#XMLID_56_);}
.st1{fill:#575756;}
.st2{fill:url(#XMLID_57_);}
.st3{fill:url(#XMLID_58_);}
.st4{fill:url(#XMLID_59_);}
</style>
<g id="XMLID_52_">
<linearGradient id="XMLID_56_" gradientUnits="userSpaceOnUse" x1="137.3219" y1="137.8237" x2="222.8845" y2="137.8237">
<stop offset="0.5" style="stop-color:#ED6D05"/>
<stop offset="1" style="stop-color:#E30613"/>
</linearGradient>
<path id="XMLID_53_" class="st0" d="M175.4,146.6c8.5-3.2,15.3-8.2,20.2-14.9c5-6.7,7.4-15,7.4-25c0-7.1-1.4-13.1-4.1-17.9
c-2.7-4.8-6.4-8.7-11.1-11.8c-4.7-3.1-9.6-5.1-14.7-5.9c-5.2-0.9-11.6-1.3-19.2-1.3h-16.7l0,15.5h0h4.5h13.1c5,0,9.1,0.4,12.4,1
c3.3,0.7,6.3,1.9,8.8,3.6c2.9,1.9,5,4.5,6.4,7.5c1.4,3.1,2.1,6.6,2.1,10.5c0,4.7-0.6,8.9-1.8,12.4c-1.2,3.5-3.1,6.6-5.7,9.1
c-2.9,2.9-6.3,4.7-10.4,5.7c-4.1,0.9-8.6,1.4-13.7,1.4h-13.1h-2.5h0l0,15.1h20.2l42.3,54h23L175.4,146.6z"/>
</g>
<g id="XMLID_42_">
<ellipse id="XMLID_51_" class="st1" cx="118.4" cy="194.7" rx="11.3" ry="11.1"/>
<path id="XMLID_50_" class="st1" d="M107.1,166.3c0-6.1,5.1-11.1,11.3-11.1c6.2,0,11.3,5,11.3,11.1c0,6.1-5.1,11.1-11.3,11.1
C112.1,177.4,107.1,172.4,107.1,166.3z"/>
<radialGradient id="XMLID_57_" cx="89.0385" cy="171.5428" r="11.3041" gradientTransform="matrix(1 0 0 0.9816 0 -2.131)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#ED6D05"/>
<stop offset="1" style="stop-color:#E8480F"/>
</radialGradient>
<path id="XMLID_49_" class="st2" d="M77.7,166.3c0-6.1,5.1-11.1,11.3-11.1c6.2,0,11.3,5,11.3,11.1c0,6.1-5.1,11.1-11.3,11.1
C82.8,177.4,77.7,172.4,77.7,166.3z"/>
<radialGradient id="XMLID_58_" cx="118.3565" cy="142.5774" r="11.3035" gradientTransform="matrix(1 0 0 0.9816 0 -2.131)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#ED6D05"/>
<stop offset="1" style="stop-color:#E8480F"/>
</radialGradient>
<ellipse id="XMLID_48_" class="st3" cx="118.4" cy="137.8" rx="11.3" ry="11.1"/>
<path id="XMLID_47_" class="st1" d="M77.7,137.8c0-6.1,5.1-11.1,11.3-11.1c6.2,0,11.3,5,11.3,11.1c0,6.1-5.1,11.1-11.3,11.1
C82.8,148.9,77.7,144,77.7,137.8z"/>
<path id="XMLID_46_" class="st1" d="M48.4,137.8c0-6.1,5.1-11.1,11.3-11.1c6.2,0,11.3,5,11.3,11.1c0,6.1-5.1,11.1-11.3,11.1
C53.5,148.9,48.4,144,48.4,137.8z"/>
<ellipse id="XMLID_45_" class="st1" cx="118.4" cy="109.4" rx="11.3" ry="11.1"/>
<radialGradient id="XMLID_59_" cx="89.0385" cy="113.6109" r="11.3046" gradientTransform="matrix(1 0 0 0.9816 0 -2.131)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#ED6D05"/>
<stop offset="1" style="stop-color:#E8480F"/>
</radialGradient>
<path id="XMLID_44_" class="st4" d="M77.7,109.4c0-6.1,5.1-11.1,11.3-11.1c6.2,0,11.3,5,11.3,11.1c0,6.1-5.1,11.1-11.3,11.1
C82.8,120.5,77.7,115.5,77.7,109.4z"/>
<ellipse id="XMLID_43_" class="st1" cx="118.4" cy="81" rx="11.3" ry="11.1"/>
</g>
<g id="XMLID_18_">
<path id="XMLID_40_" class="st1" d="M236.7,167.4h6.3v39.8h-6.3V167.4z"/>
<path id="XMLID_38_" class="st1" d="M251.2,207.2v-29h6.1v1.8c0,0,4.1-2.4,7.8-2.4c7.9,0,9.8,4.6,9.8,14.1v15.6h-6.1v-15.4
c0-5.8-0.7-8.7-5-8.7c-3.3,0-6.4,1.5-6.4,1.5v22.5H251.2z"/>
<path id="XMLID_36_" class="st1" d="M285.6,178.2l5.4,23.6h1.8l5.7-23.6h6.3l-7.4,29h-11l-7.3-29H285.6z"/>
<path id="XMLID_33_" class="st1" d="M331,201.8l0.1,4.7c0,0-6.5,1.3-11.4,1.3c-8.5,0-11.8-4.6-11.8-14.9c0-10.6,4.5-15.5,12.3-15.5
c7.9,0,11.9,4.2,11.9,13.3l-0.4,4.5h-17.6c0.1,4.6,1.8,7,6.5,7C325,202.4,331,201.8,331,201.8z M326,190.5c0-5.8-1.7-7.7-5.8-7.7
c-4.2,0-6.1,2.1-6.1,7.7H326z"/>
<path id="XMLID_31_" class="st1" d="M357.7,184.2c0,0-6.7-0.9-10.1-0.9c-3.4,0-4.9,0.8-4.9,3.2c0,1.9,1.2,2.4,6.7,3.4
c6.8,1.2,9.2,3,9.2,8.8c0,6.8-4.2,9.2-11.2,9.2c-3.9,0-10.5-1.3-10.5-1.3l0.2-5.3c0,0,6.8,0.9,9.7,0.9c4.1,0,5.7-0.9,5.7-3.4
c0-2-1-2.7-6.6-3.6c-6.2-1-9.4-2.4-9.4-8.6c0-6.6,5-9,10.6-9c4.1,0,10.7,1.3,10.7,1.3L357.7,184.2z"/>
<path id="XMLID_29_" class="st1" d="M372,183.6v12.8c0,4.4,0.2,5.9,3.1,5.9c1.6,0,4.6-0.2,4.6-0.2l0.3,5.1c0,0-3.8,0.8-5.8,0.8
c-6.4,0-8.4-2.4-8.4-10.8v-13.5h-3.6v-5.4h3.6v-8.4h6.1v8.4h7.8v5.4H372z"/>
<path id="XMLID_26_" class="st1" d="M404.4,194.9v12.4h-6.3v-39.8h14.2c8.8,0,13.2,4.4,13.2,13.4c0,9-4.4,14.1-13.2,14.1H404.4z
M412.3,189.3c4.7,0,6.8-3,6.8-8.5c0-5.5-2.1-7.8-6.8-7.8h-7.9v16.3H412.3z"/>
<path id="XMLID_23_" class="st1" d="M451.5,200.4c0.1,1.7,0.8,2.4,2.5,2.7l-0.2,4.8c-3.5,0-5.4-0.5-7.5-2.1c0,0-4.5,2.1-9.1,2.1
c-5.6,0-8.4-3.2-8.4-9.2c0-6.2,3.3-8.2,9.4-8.8l7.3-0.6v-2.1c0-3.2-1.4-4.2-4.1-4.2c-3.8,0-10.7,0.6-10.7,0.6l-0.2-4.5
c0,0,6.2-1.5,11.4-1.5c6.9,0,9.7,3,9.7,9.6V200.4z M438.8,194.3c-2.6,0.2-3.9,1.5-3.9,4.1s1.1,4.2,3.5,4.2c3.2,0,7-1.3,7-1.3v-7.7
L438.8,194.3z"/>
<path id="XMLID_21_" class="st1" d="M459.3,178.2h6.1v3.5c0,0,4.8-3.2,9.6-4.1v6.3c-5.2,1-9.6,3.1-9.6,3.1v20.3h-6.2V178.2z"/>
<path id="XMLID_19_" class="st1" d="M479.8,207.2v-41.1h6.2v23.8l3.5-0.3l6.7-11.3h6.9l-8.2,13.6l8.6,15.5h-7l-6.9-12.3l-3.7,0.4
v11.9H479.8z"/>
</g>
<g id="XMLID_4_">
<path id="XMLID_15_" class="st1" d="M239.6,119.8v33.6h-3.8V72.3h26.4c14.6,0,21.9,7,21.9,23.2c0,12.5-4.3,21.4-15.2,23.7
l16.6,34.2h-4.3l-16.4-33.6H239.6z M262.2,76.2h-22.6v39.6h22.6c13.3,0,17.9-8.3,17.9-20.4C280.1,82,274.5,76.2,262.2,76.2z"/>
<path id="XMLID_13_" class="st1" d="M336,95.5v57.9h-3.7v-4.6c0,0-8.2,5.7-17.2,5.7c-14.3,0-17.2-6.4-17.2-28.8V95.5h3.7v29.9
c0,19.7,1.9,25.4,13.6,25.4c9.4,0,17.2-5.8,17.2-5.8V95.5H336z"/>
<path id="XMLID_11_" class="st1" d="M352.6,153.4V95.5h3.7v4.6c0,0,8.2-5.7,17.2-5.7c7.8,0,11.6,1.9,14.1,6.3c0,0,9-6.3,19.3-6.3
c14.3,0,17.2,6.4,17.2,28.8v30.1h-3.7v-29.9c0-19.7-1.9-25.4-13.6-25.4c-10.2,0-18.1,5.7-18.1,5.7c1.5,4.4,1.9,10.8,1.9,19.5v30.1
h-3.7v-29.9c0-19.7-1.9-25.4-13.6-25.4c-9.4,0-17.2,5.8-17.2,5.8v49.5H352.6z"/>
<path id="XMLID_8_" class="st1" d="M440.3,72.3h3.7v6.4h-3.7V72.3z M440.3,95.5h3.7v57.9h-3.7V95.5z"/>
<path id="XMLID_5_" class="st1" d="M495.5,145.9c0.3,3.4,4.2,4.5,7.9,4.9l-0.2,3.6c-4.5,0-8.5-1.3-10.8-4.9c0,0-10.7,5-21.2,5
c-8.6,0-13.8-5.7-13.8-16.9c0-9.8,4.2-15.5,14.5-16.7l20-2.3v-6c0-10.1-4-14.1-11.7-14.1c-7.7,0-19.9,2-19.9,2l-0.3-3.8
c0,0,11.8-2.1,20.2-2.1c10.6,0,15.3,6.1,15.3,18.1V145.9z M472.2,124.4c-8.2,0.9-11,5.1-11,13.1c0,8.5,3.6,13.2,10,13.2
c9.9,0,20.6-4.8,20.6-4.8v-23.7L472.2,124.4z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="114px" height="60px" viewBox="0 0 114 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>sigma</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Sigma-HD" transform="translate(-188.000000, -51.000000)" fill-rule="nonzero">
<g id="sigma" transform="translate(188.000000, 52.500000)">
<g id="Group" transform="translate(0.000000, 16.500000)" fill="#000000">
<path d="M0.0215500945,13.8821053 L6.61587902,13.5063158 C6.76672968,14.4789474 7.04688091,15.2084211 7.4778828,15.7168421 C8.18903592,16.5347368 9.20189036,16.9547368 10.5379962,16.9547368 C11.5293006,16.9547368 12.2835539,16.7557895 12.8223062,16.3357895 C13.3610586,15.9157895 13.6196597,15.4294737 13.6196597,14.8768421 C13.6196597,14.3463158 13.3610586,13.8821053 12.8654064,13.4621053 C12.3482042,13.0421053 11.162949,12.6663158 9.30964083,12.2905263 C6.2710775,11.6715789 4.09451796,10.8536842 2.80151229,9.83684211 C1.48695652,8.82 0.840453686,7.51578947 0.840453686,5.92421053 C0.840453686,4.88526316 1.1637051,3.91263158 1.83175803,2.98421053 C2.49981096,2.05578947 3.51266541,1.32631579 4.84877127,0.795789474 C6.18487713,0.265263158 8.03818526,0 10.3655955,0 C13.231758,0 15.4083176,0.486315789 16.9168242,1.43684211 C18.4253308,2.38736842 19.3088847,3.93473684 19.610586,6.03473684 L13.0809074,6.38842105 C12.9085066,5.48210526 12.542155,4.81894737 11.9818526,4.39894737 C11.4215501,3.97894737 10.6672968,3.78 9.67599244,3.78 C8.87863894,3.78 8.2536862,3.93473684 7.8657845,4.24421053 C7.4563327,4.55368421 7.26238185,4.92947368 7.26238185,5.37157895 C7.26238185,5.70315789 7.43478261,5.99052632 7.75803403,6.23368421 C8.08128544,6.49894737 8.85708885,6.74210526 10.0854442,6.98526316 C13.1240076,7.58210526 15.279017,8.17894737 16.5935728,8.77578947 C17.9081285,9.37263158 18.8563327,10.1242105 19.4597353,11.0084211 C20.063138,11.8926316 20.3648393,12.9094737 20.3648393,13.9926316 C20.3648393,15.2968421 19.9769376,16.4905263 19.1795841,17.5736842 C18.3822306,18.6789474 17.2831758,19.4968421 15.8393195,20.0715789 C14.4170132,20.6463158 12.6068053,20.9115789 10.4302457,20.9115789 C6.61587902,20.9115789 3.96521739,20.2484211 2.49981096,18.9221053 C1.03440454,17.5957895 0.215500945,15.9157895 0.0215500945,13.8821053 Z" id="Path"></path>
<polygon id="Path" points="24.1145558 0.331578947 31.0536862 0.331578947 31.0536862 20.5578947 24.1145558 20.5578947 24.1145558 0.331578947"></polygon>
<path d="M47.3024575,13.2410526 L47.3024575,9.04105263 L58.0128544,9.04105263 L58.0128544,17.6621053 C55.9655955,18.9221053 54.1553875,19.7842105 52.5822306,20.2263158 C51.0090737,20.6905263 49.1342155,20.9115789 46.979206,20.9115789 C44.3069943,20.9115789 42.1519849,20.4915789 40.4710775,19.6736842 C38.7901701,18.8557895 37.4971645,17.64 36.5705104,16.0263158 C35.6438563,14.4126316 35.1913043,12.5557895 35.1913043,10.4557895 C35.1913043,8.24526316 35.6869565,6.32210526 36.699811,4.68631579 C37.7126654,3.05052632 39.1780718,1.81263158 41.1391304,0.972631579 C42.6476371,0.309473684 44.694896,0 47.2809074,0 C49.7591682,0 51.6124764,0.198947368 52.8408318,0.596842105 C54.0691871,0.994736842 55.0820416,1.63578947 55.9009452,2.47578947 C56.7198488,3.31578947 57.3232514,4.39894737 57.7327032,5.70315789 L51.0521739,6.78631579 C50.7720227,6.01263158 50.3194707,5.43789474 49.6514178,5.04 C48.9833648,4.64210526 48.1644612,4.44315789 47.1300567,4.44315789 C45.6,4.44315789 44.3931947,4.92947368 43.4880907,5.88 C42.5829868,6.83052632 42.1304348,8.33368421 42.1304348,10.3894737 C42.1304348,12.5778947 42.5829868,14.1473684 43.5096408,15.0757895 C44.4147448,16.0042105 45.6862004,16.4905263 47.3240076,16.4905263 C48.099811,16.4905263 48.8325142,16.38 49.5436673,16.1810526 C50.2548204,15.9821053 51.0521739,15.6284211 51.9572779,15.1421053 L51.9572779,13.2410526 L47.3024575,13.2410526 Z" id="Path"></path>
<polygon id="Path" points="62.0427221 0.331578947 71.1584121 0.331578947 74.6710775 12.6442105 78.1621928 0.331578947 87.2778828 0.331578947 87.2778828 20.5578947 81.6102079 20.5578947 81.6102079 5.12842105 77.2355388 20.5578947 72.1066163 20.5578947 67.7319471 5.12842105 67.7319471 20.5578947 62.0642722 20.5578947 62.0642722 0.331578947"></polygon>
<path d="M105.487713,17.22 L97.6219282,17.22 L96.5228733,20.5578947 L89.4544423,20.5578947 L97.8805293,0.331578947 L105.444612,0.331578947 L113.870699,20.5578947 L106.608318,20.5578947 L105.487713,17.22 Z M104.043856,12.8431579 L101.565595,5.57052632 L99.1088847,12.8431579 L104.043856,12.8431579 Z" id="Shape"></path>
</g>
<g id="Group" transform="translate(13.000000, -0.500000)" fill="#E52F29">
<polygon id="Path" points="22.2286325 48.060223 33.9688034 38.7241636 23.0271368 38.7241636 0.129487179 55.9947955 0.129487179 57.9784387 100.892094 57.9784387 100.892094 48.060223"></polygon>
<polygon id="Path" points="30.4294872 15.4594796 16.3369658 3.40669145 16.3369658 3.40669145 60.7510684 3.40669145 60.7510684 0.0431226766 0.75534188 0.0431226766 0.75534188 1.98364312 18.0418803 15.7182156"></polygon>
</g>
<g id="Group" transform="translate(37.000000, 50.500000)" fill="#FFFFFF">
<path d="M0.0652173913,0.165517241 L3.67391304,0.165517241 C4.2826087,0.165517241 4.73913043,0.289655172 5.06521739,0.55862069 C5.39130435,0.827586207 5.54347826,1.15862069 5.54347826,1.55172414 C5.54347826,1.88275862 5.43478261,2.15172414 5.19565217,2.4 C5.04347826,2.56551724 4.82608696,2.68965517 4.52173913,2.77241379 C4.97826087,2.87586207 5.30434783,3.04137931 5.5,3.26896552 C5.7173913,3.49655172 5.82608696,3.7862069 5.82608696,4.15862069 C5.82608696,4.44827586 5.76086957,4.69655172 5.60869565,4.94482759 C5.45652174,5.17241379 5.26086957,5.35862069 5,5.48275862 C4.84782609,5.56551724 4.58695652,5.62758621 4.26086957,5.66896552 C3.82608696,5.71034483 3.54347826,5.75172414 3.39130435,5.75172414 L0.0652173913,5.75172414 L0.0652173913,0.165517241 L0.0652173913,0.165517241 Z M2,2.33793103 L2.82608696,2.33793103 C3.13043478,2.33793103 3.32608696,2.29655172 3.45652174,2.19310345 C3.56521739,2.11034483 3.63043478,1.96551724 3.63043478,1.8 C3.63043478,1.63448276 3.56521739,1.51034483 3.45652174,1.42758621 C3.34782609,1.34482759 3.13043478,1.28275862 2.84782609,1.28275862 L2,1.28275862 L2,2.33793103 Z M2,4.53103448 L2.97826087,4.53103448 C3.30434783,4.53103448 3.54347826,4.46896552 3.67391304,4.36551724 C3.80434783,4.26206897 3.86956522,4.11724138 3.86956522,3.95172414 C3.86956522,3.7862069 3.80434783,3.66206897 3.67391304,3.55862069 C3.54347826,3.45517241 3.30434783,3.4137931 2.95652174,3.4137931 L1.97826087,3.4137931 L1.97826087,4.53103448 L2,4.53103448 Z" id="Shape"></path>
<path d="M10.6521739,0.165517241 L12.5652174,0.165517241 L12.5652174,3.47586207 C12.5652174,3.80689655 12.5,4.11724138 12.3913043,4.40689655 C12.2826087,4.69655172 12.0869565,4.94482759 11.8478261,5.17241379 C11.6086957,5.4 11.3478261,5.54482759 11.0869565,5.62758621 C10.7173913,5.75172414 10.2608696,5.8137931 9.73913043,5.8137931 C9.43478261,5.8137931 9.10869565,5.79310345 8.73913043,5.75172414 C8.39130435,5.71034483 8.08695652,5.64827586 7.84782609,5.52413793 C7.60869565,5.42068966 7.39130435,5.25517241 7.19565217,5.04827586 C7,4.84137931 6.86956522,4.63448276 6.7826087,4.40689655 C6.67391304,4.05517241 6.60869565,3.74482759 6.60869565,3.47586207 L6.60869565,0.165517241 L8.52173913,0.165517241 L8.52173913,3.55862069 C8.52173913,3.86896552 8.60869565,4.09655172 8.80434783,4.26206897 C9,4.42758621 9.26086957,4.51034483 9.58695652,4.51034483 C9.91304348,4.51034483 10.173913,4.42758621 10.3695652,4.26206897 C10.5652174,4.09655172 10.6521739,3.84827586 10.6521739,3.55862069 L10.6521739,0.165517241 L10.6521739,0.165517241 Z" id="Path"></path>
<path d="M13.8695652,0.165517241 L16.7173913,0.165517241 C17.2826087,0.165517241 17.7391304,0.227586207 18.0869565,0.372413793 C18.4347826,0.517241379 18.7173913,0.703448276 18.9565217,0.951724138 C19.173913,1.2 19.3478261,1.51034483 19.4565217,1.84137931 C19.5652174,2.17241379 19.6086957,2.54482759 19.6086957,2.91724138 C19.6086957,3.51724138 19.5434783,3.97241379 19.3913043,4.30344828 C19.2391304,4.63448276 19.0217391,4.90344828 18.7608696,5.13103448 C18.5,5.35862069 18.1956522,5.50344828 17.8913043,5.56551724 C17.4782609,5.66896552 17.0869565,5.71034483 16.7391304,5.71034483 L13.8913043,5.71034483 L13.8913043,0.165517241 L13.8695652,0.165517241 Z M15.7826087,1.42758621 L15.7826087,4.46896552 L16.2608696,4.46896552 C16.6521739,4.46896552 16.9565217,4.42758621 17.1086957,4.34482759 C17.2826087,4.26206897 17.4130435,4.11724138 17.5,3.93103448 C17.5869565,3.72413793 17.6521739,3.4137931 17.6521739,2.95862069 C17.6521739,2.37931034 17.5434783,1.96551724 17.326087,1.75862069 C17.1086957,1.55172414 16.7608696,1.42758621 16.2608696,1.42758621 L15.7826087,1.42758621 Z" id="Shape"></path>
<path d="M20.3478261,2.93793103 C20.3478261,2.02758621 20.6304348,1.32413793 21.1956522,0.827586207 C21.7608696,0.331034483 22.5434783,0.0620689655 23.5652174,0.0620689655 C24.6086957,0.0620689655 25.3913043,0.310344828 25.9565217,0.806896552 C26.5217391,1.30344828 26.8043478,2.00689655 26.8043478,2.89655172 C26.8043478,3.53793103 26.673913,4.07586207 26.4347826,4.48965517 C26.1956522,4.90344828 25.826087,5.23448276 25.3695652,5.46206897 C24.9130435,5.68965517 24.326087,5.8137931 23.6304348,5.8137931 C22.9347826,5.8137931 22.3478261,5.71034483 21.8913043,5.52413793 C21.4347826,5.31724138 21.0652174,5.00689655 20.7826087,4.57241379 C20.5,4.13793103 20.3478261,3.6 20.3478261,2.93793103 Z M22.2826087,2.95862069 C22.2826087,3.51724138 22.3913043,3.93103448 22.6304348,4.15862069 C22.8695652,4.40689655 23.173913,4.53103448 23.5869565,4.53103448 C24,4.53103448 24.326087,4.40689655 24.5434783,4.17931034 C24.7608696,3.93103448 24.8913043,3.51724138 24.8913043,2.89655172 C24.8913043,2.37931034 24.7826087,1.9862069 24.5434783,1.75862069 C24.3043478,1.51034483 23.9782609,1.40689655 23.5869565,1.40689655 C23.1956522,1.40689655 22.8913043,1.53103448 22.6521739,1.77931034 C22.3913043,1.9862069 22.2826087,2.4 22.2826087,2.95862069 Z" id="Shape"></path>
<polygon id="Path" points="27.0434783 0.165517241 28.8695652 0.165517241 29.5217391 3.26896552 30.4782609 0.165517241 32.3043478 0.165517241 33.2608696 3.26896552 33.9130435 0.165517241 35.7391304 0.165517241 34.3695652 5.71034483 32.4782609 5.71034483 31.3913043 2.2137931 30.3043478 5.71034483 28.4130435 5.71034483"></polygon>
<polygon id="Path" points="36.3913043 0.165517241 38.1956522 0.165517241 40.5434783 3.22758621 40.5434783 0.165517241 42.3478261 0.165517241 42.3478261 5.71034483 40.5434783 5.71034483 38.2173913 2.66896552 38.2173913 5.71034483 36.4130435 5.71034483 36.4130435 0.165517241"></polygon>
<polygon id="Path" points="43.6956522 0.165517241 45.6304348 0.165517241 45.6304348 5.71034483 43.6956522 5.71034483"></polygon>
<path d="M51.1521739,3.45517241 L52.826087,3.91034483 C52.7173913,4.32413793 52.5434783,4.67586207 52.2826087,4.96551724 C52.0434783,5.25517241 51.7391304,5.46206897 51.3695652,5.60689655 C51,5.75172414 50.5434783,5.8137931 50,5.8137931 C49.326087,5.8137931 48.7608696,5.73103448 48.3478261,5.54482759 C47.9130435,5.37931034 47.5434783,5.06896552 47.2391304,4.6137931 C46.9347826,4.17931034 46.7826087,3.6 46.7826087,2.91724138 C46.7826087,2.00689655 47.0652174,1.30344828 47.6086957,0.806896552 C48.1521739,0.310344828 48.9347826,0.0620689655 49.9347826,0.0620689655 C50.7173913,0.0620689655 51.326087,0.206896552 51.7826087,0.475862069 C52.2391304,0.765517241 52.5652174,1.2 52.7826087,1.77931034 L51.0869565,2.11034483 C51.0217391,1.94482759 50.9565217,1.82068966 50.8913043,1.73793103 C50.7826087,1.6137931 50.6521739,1.51034483 50.5,1.42758621 C50.3478261,1.36551724 50.173913,1.32413793 49.9782609,1.32413793 C49.5434783,1.32413793 49.2173913,1.48965517 48.9782609,1.8 C48.8043478,2.02758621 48.7173913,2.4 48.7173913,2.89655172 C48.7173913,3.51724138 48.826087,3.93103448 49.0217391,4.15862069 C49.2391304,4.3862069 49.5217391,4.51034483 49.9130435,4.51034483 C50.2826087,4.51034483 50.5652174,4.42758621 50.7391304,4.24137931 C50.9130435,4.07586207 51.0652174,3.80689655 51.1521739,3.45517241 Z" id="Path"></path>
<polygon id="Path" points="53.326087 0.165517241 59.173913 0.165517241 59.173913 1.53103448 57.2173913 1.53103448 57.2173913 5.71034483 55.3043478 5.71034483 55.3043478 1.53103448 53.3478261 1.53103448 53.3478261 0.165517241"></polygon>
<polygon id="Path" points="59.3913043 0.165517241 61.2173913 0.165517241 61.8695652 3.26896552 62.826087 0.165517241 64.6521739 0.165517241 65.6086957 3.26896552 66.2608696 0.165517241 68.0869565 0.165517241 66.7173913 5.71034483 64.826087 5.71034483 63.7391304 2.2137931 62.6521739 5.71034483 60.7608696 5.71034483"></polygon>
<path d="M68.3478261,2.93793103 C68.3478261,2.02758621 68.6304348,1.32413793 69.1956522,0.827586207 C69.7608696,0.331034483 70.5434783,0.0620689655 71.5652174,0.0620689655 C72.6086957,0.0620689655 73.3913043,0.310344828 73.9565217,0.806896552 C74.5217391,1.30344828 74.8043478,2.00689655 74.8043478,2.89655172 C74.8043478,3.53793103 74.673913,4.07586207 74.4347826,4.48965517 C74.1956522,4.90344828 73.826087,5.23448276 73.3695652,5.46206897 C72.9130435,5.68965517 72.326087,5.8137931 71.6304348,5.8137931 C70.9347826,5.8137931 70.3478261,5.71034483 69.8913043,5.52413793 C69.4347826,5.31724138 69.0652174,5.00689655 68.7826087,4.57241379 C68.4782609,4.13793103 68.3478261,3.6 68.3478261,2.93793103 Z M70.2608696,2.95862069 C70.2608696,3.51724138 70.3695652,3.93103448 70.6086957,4.15862069 C70.8478261,4.40689655 71.1521739,4.53103448 71.5652174,4.53103448 C71.9782609,4.53103448 72.3043478,4.40689655 72.5217391,4.17931034 C72.7391304,3.93103448 72.8695652,3.51724138 72.8695652,2.89655172 C72.8695652,2.37931034 72.7608696,1.9862069 72.5217391,1.75862069 C72.2826087,1.51034483 71.9565217,1.40689655 71.5652174,1.40689655 C71.173913,1.40689655 70.8695652,1.53103448 70.6304348,1.77931034 C70.3695652,1.9862069 70.2608696,2.4 70.2608696,2.95862069 Z" id="Shape"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 205.073 43.761"><path fill-rule="evenodd" clip-rule="evenodd" fill="#004987" d="M22.029 43.754l18.876-27.112 4.753 27.112h14.506l22.489-32.083h36.259c6 0 9.516 6.792 6.073 11.735a20.211 20.211 0 0 1-16.586 8.684H89.99l9.182-13.127H84.733L67.375 43.754h40.077c11.263-.085 21.798-5.642 28.264-14.93 8.452-12.139-.183-28.822-14.917-28.822H76.173L57.244 27.118 52.489.002H37.987L19.109 27.118 14.502.002H0l7.524 43.752h14.505z"></path><path fill-rule="evenodd" clip-rule="evenodd" fill="#004987" d="M127.475 43.761h20.504l28.452-21.823L155.613 0h-18.111L157.3 20.863z"></path><path fill-rule="evenodd" clip-rule="evenodd" fill="#FF5F00" d="M180.555 18.795L205.073.006H184.48l-12.571 9.678zM179.459 25.129l-10.5 8.017 10.07 10.59 18.074-.019z"></path></svg>

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

0
templates/admin/announcements.html Normal file → Executable file
View File

0
templates/admin/announcements_form.html Normal file → Executable file
View File

0
templates/admin/chat_analytics.html Normal file → Executable file
View File

0
templates/admin/debug.html Normal file → Executable file
View File

0
templates/admin/digital_maturity.html Normal file → Executable file
View File

0
templates/admin/fees.html Normal file → Executable file
View File

0
templates/admin/forum.html Normal file → Executable file
View File

View File

@ -0,0 +1,616 @@
{% extends "base.html" %}
{% block title %}Moderacja Rekomendacji - Norda Biznes Hub{% endblock %}
{% block extra_css %}
<style>
.admin-header {
margin-bottom: var(--spacing-xl);
}
.admin-header h1 {
font-size: var(--font-size-3xl);
color: var(--text-primary);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: var(--spacing-lg);
margin-bottom: var(--spacing-2xl);
}
.stat-card {
background: var(--surface);
padding: var(--spacing-lg);
border-radius: var(--radius-lg);
box-shadow: var(--shadow);
text-align: center;
}
.stat-value {
font-size: var(--font-size-3xl);
font-weight: 700;
color: var(--primary);
}
.stat-label {
color: var(--text-secondary);
font-size: var(--font-size-sm);
margin-top: var(--spacing-xs);
}
.filter-tabs {
display: flex;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-lg);
border-bottom: 2px solid var(--border);
padding-bottom: var(--spacing-sm);
}
.filter-tab {
padding: var(--spacing-sm) var(--spacing-md);
background: transparent;
border: none;
color: var(--text-secondary);
cursor: pointer;
font-size: var(--font-size-base);
font-weight: 500;
transition: var(--transition);
border-bottom: 2px solid transparent;
margin-bottom: -2px;
}
.filter-tab:hover {
color: var(--text-primary);
}
.filter-tab.active {
color: var(--primary);
border-bottom-color: var(--primary);
}
.section {
background: var(--surface);
padding: var(--spacing-xl);
border-radius: var(--radius-lg);
box-shadow: var(--shadow);
margin-bottom: var(--spacing-xl);
}
.section h2 {
font-size: var(--font-size-xl);
margin-bottom: var(--spacing-lg);
color: var(--text-primary);
border-bottom: 2px solid var(--border);
padding-bottom: var(--spacing-sm);
}
.recommendations-table {
width: 100%;
border-collapse: collapse;
}
.recommendations-table th,
.recommendations-table td {
padding: var(--spacing-md);
text-align: left;
border-bottom: 1px solid var(--border);
}
.recommendations-table th {
font-weight: 600;
color: var(--text-secondary);
font-size: var(--font-size-sm);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.recommendations-table tr:hover {
background: var(--background);
}
.recommendation-text {
max-width: 300px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
font-size: var(--font-size-sm);
color: var(--text-primary);
line-height: 1.4;
}
.recommendation-meta {
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
.recommendation-company {
font-weight: 500;
color: var(--text-primary);
text-decoration: none;
}
.recommendation-company:hover {
color: var(--primary);
}
.badge {
display: inline-block;
padding: 2px 8px;
border-radius: var(--radius-sm);
font-size: var(--font-size-xs);
font-weight: 500;
text-transform: uppercase;
}
.badge-pending {
background: #FEF3C7;
color: #92400E;
}
.badge-approved {
background: #D1FAE5;
color: #065F46;
}
.badge-rejected {
background: #FEE2E2;
color: #991B1B;
}
.action-buttons {
display: flex;
gap: var(--spacing-xs);
}
.btn-icon {
width: 32px;
height: 32px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--surface);
cursor: pointer;
transition: var(--transition);
}
.btn-icon:hover {
background: var(--background);
}
.btn-icon.approve {
background: #D1FAE5;
border-color: #10B981;
color: #065F46;
}
.btn-icon.approve:hover {
background: #10B981;
color: white;
}
.btn-icon.reject {
background: #FEE2E2;
border-color: #EF4444;
color: #991B1B;
}
.btn-icon.reject:hover {
background: #EF4444;
color: white;
}
.btn-icon.danger:hover {
background: var(--error);
border-color: var(--error);
color: white;
}
.btn-icon svg {
width: 16px;
height: 16px;
}
.empty-state {
text-align: center;
padding: var(--spacing-2xl);
color: var(--text-secondary);
}
/* Modal for rejection reason */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
align-items: center;
justify-content: center;
}
.modal.active {
display: flex;
}
.modal-content {
background: var(--surface);
padding: var(--spacing-xl);
border-radius: var(--radius-lg);
max-width: 500px;
width: 90%;
box-shadow: var(--shadow-lg);
}
.modal-header {
font-size: var(--font-size-xl);
margin-bottom: var(--spacing-md);
color: var(--text-primary);
}
.modal-body {
margin-bottom: var(--spacing-lg);
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-sm);
}
.form-group {
margin-bottom: var(--spacing-md);
}
.form-label {
display: block;
margin-bottom: var(--spacing-xs);
color: var(--text-secondary);
font-size: var(--font-size-sm);
font-weight: 500;
}
.form-control {
width: 100%;
padding: var(--spacing-sm);
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: var(--font-size-base);
font-family: inherit;
resize: vertical;
}
.form-control:focus {
outline: none;
border-color: var(--primary);
}
.btn {
padding: var(--spacing-sm) var(--spacing-md);
border: none;
border-radius: var(--radius);
font-size: var(--font-size-base);
font-weight: 500;
cursor: pointer;
transition: var(--transition);
}
.btn-primary {
background: var(--primary);
color: white;
}
.btn-primary:hover {
opacity: 0.9;
}
.btn-secondary {
background: var(--background);
color: var(--text-secondary);
}
.btn-secondary:hover {
background: var(--border);
}
@media (max-width: 768px) {
.recommendations-table {
font-size: var(--font-size-sm);
}
.recommendations-table th:nth-child(3),
.recommendations-table td:nth-child(3) {
display: none;
}
.recommendation-text {
max-width: 200px;
}
}
</style>
{% endblock %}
{% block content %}
<div class="admin-header">
<h1>⭐ Moderacja Rekomendacji</h1>
<p class="text-muted">Zarządzaj rekomendacjami firm członkowskich</p>
</div>
<!-- Stats Grid -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value">{{ total_recommendations }}</div>
<div class="stat-label">Wszystkich</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #F59E0B;">{{ pending_count }}</div>
<div class="stat-label">Oczekujących</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #10B981;">{{ approved_count }}</div>
<div class="stat-label">Zatwierdzonych</div>
</div>
<div class="stat-card">
<div class="stat-value" style="color: #EF4444;">{{ rejected_count }}</div>
<div class="stat-label">Odrzuconych</div>
</div>
</div>
<!-- Recommendations Section -->
<div class="section">
<h2>Rekomendacje</h2>
<!-- Filter Tabs -->
<div class="filter-tabs">
<button class="filter-tab active" data-filter="all">Wszystkie</button>
<button class="filter-tab" data-filter="pending">Oczekujące ({{ pending_count }})</button>
<button class="filter-tab" data-filter="approved">Zatwierdzone ({{ approved_count }})</button>
<button class="filter-tab" data-filter="rejected">Odrzucone ({{ rejected_count }})</button>
</div>
{% if recommendations %}
<table class="recommendations-table">
<thead>
<tr>
<th>Firma</th>
<th>Rekomendujący</th>
<th>Treść</th>
<th>Data</th>
<th>Status</th>
<th>Akcje</th>
</tr>
</thead>
<tbody>
{% for rec in recommendations %}
<tr data-recommendation-id="{{ rec.id }}" data-status="{{ rec.status }}">
<td>
<a href="{{ url_for('company_detail_by_slug', slug=rec.company.slug) }}"
class="recommendation-company"
target="_blank">
{{ rec.company.name }}
</a>
{% if rec.service_category %}
<div class="recommendation-meta">{{ rec.service_category }}</div>
{% endif %}
</td>
<td>
<div class="recommendation-meta">
{{ rec.user.name or rec.user.email.split('@')[0] }}
{% if rec.user.company %}
<br>{{ rec.user.company.name }}
{% endif %}
</div>
</td>
<td>
<div class="recommendation-text" title="{{ rec.recommendation_text }}">
{{ rec.recommendation_text }}
</div>
</td>
<td class="recommendation-meta">{{ rec.created_at.strftime('%d.%m.%Y') }}</td>
<td>
{% if rec.status == 'pending' %}
<span class="badge badge-pending">Oczekuje</span>
{% elif rec.status == 'approved' %}
<span class="badge badge-approved">Zatwierdzona</span>
{% elif rec.status == 'rejected' %}
<span class="badge badge-rejected">Odrzucona</span>
{% endif %}
</td>
<td>
<div class="action-buttons">
{% if rec.status == 'pending' %}
<button class="btn-icon approve"
onclick="approveRecommendation({{ rec.id }})"
title="Zatwierdź">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</button>
<button class="btn-icon reject"
onclick="openRejectModal({{ rec.id }}, '{{ rec.company.name|e }}')"
title="Odrzuć">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
{% elif rec.status == 'rejected' %}
<button class="btn-icon approve"
onclick="approveRecommendation({{ rec.id }})"
title="Zatwierdź">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</button>
{% endif %}
<button class="btn-icon danger"
onclick="deleteRecommendation({{ rec.id }}, '{{ rec.company.name|e }}')"
title="Usuń">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
</svg>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="empty-state">
<p>Brak rekomendacji</p>
</div>
{% endif %}
</div>
<!-- Rejection Modal -->
<div id="rejectModal" class="modal">
<div class="modal-content">
<div class="modal-header">Odrzuć rekomendację</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">Powód odrzucenia (opcjonalnie)</label>
<textarea id="rejectionReason"
class="form-control"
rows="4"
placeholder="Wprowadź powód odrzucenia..."></textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" onclick="closeRejectModal()">Anuluj</button>
<button class="btn btn-primary" onclick="confirmReject()">Odrzuć</button>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
const csrfToken = '{{ csrf_token() }}';
let currentRecommendationId = null;
function showMessage(message, type) {
// Simple alert for now - could be improved with toast notifications
alert(message);
}
// Filter tabs functionality
document.querySelectorAll('.filter-tab').forEach(tab => {
tab.addEventListener('click', function() {
// Update active tab
document.querySelectorAll('.filter-tab').forEach(t => t.classList.remove('active'));
this.classList.add('active');
// Filter rows
const filter = this.dataset.filter;
document.querySelectorAll('[data-recommendation-id]').forEach(row => {
if (filter === 'all' || row.dataset.status === filter) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
});
});
async function approveRecommendation(recommendationId) {
try {
const response = await fetch(`/admin/recommendations/${recommendationId}/approve`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
}
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
showMessage(data.error || 'Wystąpił błąd', 'error');
}
} catch (error) {
showMessage('Błąd połączenia', 'error');
}
}
function openRejectModal(recommendationId, companyName) {
currentRecommendationId = recommendationId;
document.getElementById('rejectionReason').value = '';
document.getElementById('rejectModal').classList.add('active');
}
function closeRejectModal() {
currentRecommendationId = null;
document.getElementById('rejectModal').classList.remove('active');
}
async function confirmReject() {
if (!currentRecommendationId) return;
const reason = document.getElementById('rejectionReason').value.trim();
try {
const response = await fetch(`/admin/recommendations/${currentRecommendationId}/reject`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ reason: reason })
});
const data = await response.json();
if (data.success) {
closeRejectModal();
location.reload();
} else {
showMessage(data.error || 'Wystąpił błąd', 'error');
}
} catch (error) {
showMessage('Błąd połączenia', 'error');
}
}
async function deleteRecommendation(recommendationId, companyName) {
if (!confirm(`Czy na pewno chcesz usunąć rekomendację dla firmy "${companyName}"?\n\nTa operacja jest nieodwracalna.`)) {
return;
}
try {
const response = await fetch(`/api/recommendations/${recommendationId}/delete`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
}
});
const data = await response.json();
if (data.success) {
document.querySelector(`tr[data-recommendation-id="${recommendationId}"]`).remove();
showMessage('Rekomendacja została usunięta', 'success');
} else {
showMessage(data.error || 'Wystąpił błąd', 'error');
}
} catch (error) {
showMessage('Błąd połączenia', 'error');
}
}
// Close modal on background click
document.getElementById('rejectModal').addEventListener('click', function(e) {
if (e.target === this) {
closeRejectModal();
}
});
{% endblock %}

0
templates/admin/social_media.html Normal file → Executable file
View File

0
templates/announcements/list.html Normal file → Executable file
View File

0
templates/auth/forgot_password.html Normal file → Executable file
View File

0
templates/auth/login.html Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More