Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14bd394982 | ||
|
|
8b287bb81e | ||
|
|
05d5cf06f1 | ||
|
|
a5f6bcfbfb | ||
|
|
a8ecf86b7b | ||
|
|
914de83657 | ||
|
|
1aeacf5346 | ||
|
|
d4b0d59cdf | ||
|
|
3e13efe7c9 | ||
|
|
a1b931b542 | ||
|
|
7a4ff904d7 | ||
|
|
450abc0cf9 | ||
|
|
1c2ee7d646 | ||
|
|
2dec8bf20a | ||
|
|
71eddb004d | ||
|
|
f72f330bc7 | ||
|
|
96986d7adb | ||
|
|
0bf9821d17 | ||
|
|
af2904cd39 | ||
|
|
e671155120 | ||
|
|
7225b97b8c | ||
|
|
b3d87ac5de | ||
|
|
9424a7b98c | ||
|
|
53e9b9d640 | ||
|
|
77a519c27d | ||
|
|
e27413880a | ||
|
|
8441cc702c | ||
|
|
28222ee7f1 | ||
|
|
79613cadfe |
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddSuperadminAndSchoolRoles extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// 1) Flag superadmin di piattaforma (gestore del portale)
|
||||||
|
$this->table('auth_users')
|
||||||
|
->addColumn('is_superadmin', 'char', [
|
||||||
|
'limit' => 1,
|
||||||
|
'default' => 'N',
|
||||||
|
'null' => false,
|
||||||
|
'comment' => 'Y = gestore piattaforma, vede tutte le scuole',
|
||||||
|
])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// 2) Ruoli nella scuola 1 ricavati dai ruoli Vanguard attuali
|
||||||
|
$this->execute("
|
||||||
|
UPDATE school_user su
|
||||||
|
JOIN auth_users u ON u.id = su.user_id
|
||||||
|
JOIN auth_roles r ON r.id = u.role_id
|
||||||
|
SET su.school_role = CASE
|
||||||
|
WHEN LOWER(r.name) = 'admin' THEN 'admin'
|
||||||
|
WHEN LOWER(r.name) = 'teacher' THEN 'teacher'
|
||||||
|
ELSE 'student'
|
||||||
|
END
|
||||||
|
WHERE su.idschool = 1
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->execute("UPDATE school_user SET school_role = 'student' WHERE idschool = 1");
|
||||||
|
|
||||||
|
$this->table('auth_users')
|
||||||
|
->removeColumn('is_superadmin')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class ExtendSchoolsProfile extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// 1) Anagrafica e pagina pubblica della scuola
|
||||||
|
$this->table('schools')
|
||||||
|
->addColumn('legal_name', 'string', ['limit' => 191, 'null' => true, 'comment' => 'ragione sociale'])
|
||||||
|
->addColumn('tax_code', 'string', ['limit' => 20, 'null' => true, 'comment' => 'codice fiscale'])
|
||||||
|
->addColumn('sdi_code', 'string', ['limit' => 7, 'null' => true, 'comment' => 'codice destinatario SDI'])
|
||||||
|
->addColumn('pec', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('whatsapp', 'string', ['limit' => 30, 'null' => true])
|
||||||
|
->addColumn('province', 'string', ['limit' => 50, 'null' => true])
|
||||||
|
->addColumn('lat', 'decimal', ['precision' => 10, 'scale' => 7, 'null' => true])
|
||||||
|
->addColumn('lng', 'decimal', ['precision' => 10, 'scale' => 7, 'null' => true])
|
||||||
|
->addColumn('short_description', 'string', ['limit' => 255, 'null' => true, 'comment' => 'slogan / sottotitolo'])
|
||||||
|
->addColumn('description', 'text', ['null' => true, 'comment' => 'descrizione scuola'])
|
||||||
|
->addColumn('courses_description', 'text', ['null' => true, 'comment' => 'descrizione corsi'])
|
||||||
|
->addColumn('opening_hours', 'text', ['null' => true, 'comment' => 'orari (testo libero)'])
|
||||||
|
->addColumn('website', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('instagram', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('facebook', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('youtube', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// 2) Galleria immagini (max 10 per scuola, limite applicato dall'app)
|
||||||
|
$this->table('school_images', [
|
||||||
|
'id' => false,
|
||||||
|
'primary_key' => ['idimage'],
|
||||||
|
'engine' => 'InnoDB',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
])
|
||||||
|
->addColumn('idimage', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('filename', 'string', ['limit' => 191])
|
||||||
|
->addColumn('is_cover', 'char', ['limit' => 1, 'default' => 'N'])
|
||||||
|
->addColumn('sort_order', 'integer', ['default' => 0])
|
||||||
|
->addColumn('created_at', 'timestamp', ['null' => true, 'default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool'], ['name' => 'school_images_idschool_index'])
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', ['delete' => 'CASCADE', 'update' => 'NO_ACTION'])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// 3) Colori del tema (NULL = colori standard del template)
|
||||||
|
$this->table('option')
|
||||||
|
->addColumn('theme_primary', 'string', ['limit' => 7, 'null' => true])
|
||||||
|
->addColumn('theme_sidebar', 'string', ['limit' => 7, 'null' => true])
|
||||||
|
->addColumn('theme_topbar', 'string', ['limit' => 7, 'null' => true])
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->removeColumn('theme_primary')
|
||||||
|
->removeColumn('theme_sidebar')
|
||||||
|
->removeColumn('theme_topbar')
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('school_images')->drop()->save();
|
||||||
|
|
||||||
|
$this->table('schools')
|
||||||
|
->removeColumn('legal_name')
|
||||||
|
->removeColumn('tax_code')
|
||||||
|
->removeColumn('sdi_code')
|
||||||
|
->removeColumn('pec')
|
||||||
|
->removeColumn('whatsapp')
|
||||||
|
->removeColumn('province')
|
||||||
|
->removeColumn('lat')
|
||||||
|
->removeColumn('lng')
|
||||||
|
->removeColumn('short_description')
|
||||||
|
->removeColumn('description')
|
||||||
|
->removeColumn('courses_description')
|
||||||
|
->removeColumn('opening_hours')
|
||||||
|
->removeColumn('website')
|
||||||
|
->removeColumn('instagram')
|
||||||
|
->removeColumn('facebook')
|
||||||
|
->removeColumn('youtube')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class FixDayoffAndServiceDefaults extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// 1) dayoff: rimuove i duplicati (tiene il primo) e rende unico (scuola, giorno)
|
||||||
|
$this->execute("
|
||||||
|
DELETE d1 FROM dayoff d1
|
||||||
|
JOIN dayoff d2
|
||||||
|
ON d1.idschool = d2.idschool
|
||||||
|
AND d1.dayoffdate = d2.dayoffdate
|
||||||
|
AND d1.iddayoff > d2.iddayoff
|
||||||
|
");
|
||||||
|
$this->table('dayoff')
|
||||||
|
->addIndex(['idschool', 'dayoffdate'], ['unique' => true, 'name' => 'dayoff_school_date_unique'])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// 2) service: default per colonne NOT NULL che il form può lasciare vuote
|
||||||
|
$this->table('service')
|
||||||
|
->changeColumn('category', 'integer', ['null' => false, 'default' => 0])
|
||||||
|
->changeColumn('idlocation', 'float', ['null' => false, 'default' => 0])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// 3) Indice per le ricerche delle lezioni per servizio e data
|
||||||
|
$this->table('serviceschedule')
|
||||||
|
->addIndex(['idschool', 'idservice', 'dateschedule'], ['name' => 'serviceschedule_school_service_date'])
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('serviceschedule')
|
||||||
|
->removeIndexByName('serviceschedule_school_service_date')
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('service')
|
||||||
|
->changeColumn('category', 'integer', ['null' => false])
|
||||||
|
->changeColumn('idlocation', 'float', ['null' => false])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('dayoff')
|
||||||
|
->removeIndexByName('dayoff_school_date_unique')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class AddStudentNoticeAndShopUrl extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->addColumn('student_notice', 'text', ['null' => true, 'comment' => 'avviso mostrato agli allievi nel pannello prenotazioni'])
|
||||||
|
->addColumn('shop_url', 'string', ['limit' => 255, 'null' => true, 'comment' => 'link esterno per acquistare pacchetti'])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// Seregno: riporta i testi finora scritti nel codice
|
||||||
|
$this->execute("
|
||||||
|
UPDATE `option`
|
||||||
|
SET student_notice = 'Car* Yogi, ti ricordiamo che il pacchetto 4 lezioni ha validità entro 5 settimane e il pacchetto da 12 lezioni entro 15 settimane dalla prima lezione 🙏',
|
||||||
|
shop_url = 'https://yogasoul.it/shop-completo/'
|
||||||
|
WHERE idschool = 1
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->removeColumn('student_notice')
|
||||||
|
->removeColumn('shop_url')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chiave pubblica per il plugin WordPress: identifica la scuola negli endpoint
|
||||||
|
* apiwp (lista eventi e prenotazione), dove non c'è sessione.
|
||||||
|
* Genera una chiave per ogni scuola già esistente.
|
||||||
|
*
|
||||||
|
* NOTA: questo file è solo il contenuto da incollare nella migration creata con
|
||||||
|
* php vendor/bin/phinx create AddWidgetKeyToSchools
|
||||||
|
* (tieni il nome file con il timestamp generato da phinx).
|
||||||
|
*/
|
||||||
|
final class AddWidgetKeyToSchools extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->table('schools')
|
||||||
|
->addColumn('widget_key', 'string', ['limit' => 64, 'null' => true])
|
||||||
|
->addIndex(['widget_key'], ['unique' => true, 'name' => 'uq_schools_widget_key'])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$rows = $this->fetchAll('SELECT idschool FROM schools');
|
||||||
|
foreach ($rows as $r) {
|
||||||
|
// Valori generati qui (esadecimale e intero): nessun dato esterno nell'SQL
|
||||||
|
$key = bin2hex(random_bytes(16));
|
||||||
|
$this->execute(
|
||||||
|
"UPDATE schools SET widget_key = '" . $key . "' WHERE idschool = " . (int) $r['idschool']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('schools')
|
||||||
|
->removeIndexByName('uq_schools_widget_key')
|
||||||
|
->removeColumn('widget_key')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domini dei siti WordPress autorizzati a usare il widget eventi (CORS), per scuola.
|
||||||
|
* Formato: origini separate da virgola, senza spazi, es. "https://sito.it,https://www.sito.it".
|
||||||
|
* Seregno riceve i domini che prima erano scritti in apiwp/bootstrap.php.
|
||||||
|
*
|
||||||
|
* NOTA: contenuto da incollare nella migration creata con
|
||||||
|
* php vendor/bin/phinx create AddWidgetOriginsToSchools
|
||||||
|
*/
|
||||||
|
final class AddWidgetOriginsToSchools extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->table('schools')
|
||||||
|
->addColumn('widget_origins', 'string', ['limit' => 1000, 'null' => true])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->execute(
|
||||||
|
"UPDATE schools SET widget_origins = 'https://yogasoul.it,https://www.yogasoul.it' WHERE idschool = 1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('schools')
|
||||||
|
->removeColumn('widget_origins')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La migration CreateSchoolUserTable ha iscritto tutti gli utenti esistenti
|
||||||
|
* con joined_at = data della migration: nella dashboard sembrerebbero tutti "nuovi".
|
||||||
|
* Qui si usa la data di registrazione dell'account (auth_users.created_at), se precedente.
|
||||||
|
*
|
||||||
|
* NOTA: contenuto da incollare nella migration creata con
|
||||||
|
* php vendor/bin/phinx create FixSchoolUserJoinedAt
|
||||||
|
*/
|
||||||
|
final class FixSchoolUserJoinedAt extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->execute(
|
||||||
|
"UPDATE school_user su
|
||||||
|
JOIN auth_users u ON u.id = su.user_id
|
||||||
|
SET su.joined_at = u.created_at
|
||||||
|
WHERE u.created_at IS NOT NULL
|
||||||
|
AND u.created_at < su.joined_at"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
// Nessun ripristino: la data precedente era solo quella della migration
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Db\Adapter\MysqlAdapter;
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catalogo prodotti YogiBook:
|
||||||
|
* prodotti, varianti, classi valide, immagini, classi scelte nei pacchetti fissi,
|
||||||
|
* tessere, buoni regalo, coupon. Estende orderbook e option.
|
||||||
|
*/
|
||||||
|
final class CreateProductCatalog extends AbstractMigration
|
||||||
|
{
|
||||||
|
private const OPT = [
|
||||||
|
'id' => false,
|
||||||
|
'engine' => 'InnoDB',
|
||||||
|
'encoding' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
];
|
||||||
|
|
||||||
|
private const CASCADE = ['delete' => 'CASCADE', 'update' => 'NO_ACTION'];
|
||||||
|
private const SETNULL = ['delete' => 'SET_NULL', 'update' => 'NO_ACTION'];
|
||||||
|
private const RESTRICT = ['delete' => 'RESTRICT', 'update' => 'NO_ACTION'];
|
||||||
|
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// products: la scheda di vendita + le regole
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('products', self::OPT + ['primary_key' => ['idproduct']])
|
||||||
|
->addColumn('idproduct', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('kind', 'string', ['limit' => 20, 'default' => 'lessons', 'comment' => 'lessons|membership|voucher'])
|
||||||
|
// presentazione
|
||||||
|
->addColumn('title', 'string', ['limit' => 191])
|
||||||
|
->addColumn('subtitle', 'string', ['limit' => 255, 'null' => true])
|
||||||
|
->addColumn('slug', 'string', ['limit' => 191])
|
||||||
|
->addColumn('description', 'text', ['limit' => MysqlAdapter::TEXT_LONG, 'null' => true, 'comment' => 'HTML editor'])
|
||||||
|
->addColumn('suitable_for', 'text', ['null' => true, 'comment' => 'per chi e'])
|
||||||
|
->addColumn('pros', 'text', ['null' => true, 'comment' => 'vantaggi, uno per riga'])
|
||||||
|
->addColumn('cons', 'text', ['null' => true, 'comment' => 'da considerare, uno per riga'])
|
||||||
|
->addColumn('requirements', 'text', ['null' => true, 'comment' => 'cosa serve / cosa portare'])
|
||||||
|
->addColumn('cover_image', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('badge', 'string', ['limit' => 50, 'null' => true, 'comment' => 'es. Il piu scelto'])
|
||||||
|
// regole
|
||||||
|
->addColumn('booking_mode', 'string', ['limit' => 10, 'default' => 'free', 'comment' => 'fixed|free|single'])
|
||||||
|
->addColumn('fixed_slots', 'integer', ['default' => 1, 'comment' => 'classi fisse a settimana (fixed)'])
|
||||||
|
->addColumn('weekly_limit', 'integer', ['null' => true, 'comment' => 'max lezioni a settimana, NULL = nessuno'])
|
||||||
|
->addColumn('max_reschedule', 'integer', ['null' => true, 'comment' => 'recuperi, NULL = default scuola'])
|
||||||
|
->addColumn('once_per_student', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = es. lezione di prova'])
|
||||||
|
// visibilita
|
||||||
|
->addColumn('visible_online', 'string', ['limit' => 1, 'default' => 'Y'])
|
||||||
|
->addColumn('active', 'string', ['limit' => 1, 'default' => 'Y'])
|
||||||
|
->addColumn('sort_order', 'integer', ['default' => 0])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool', 'slug'], ['unique' => true, 'name' => 'products_school_slug_unique'])
|
||||||
|
->addIndex(['idschool', 'active'], ['name' => 'products_school_active'])
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// product_variants: le opzioni acquistabili (prezzo, lezioni, durata)
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('product_variants', self::OPT + ['primary_key' => ['idvariant']])
|
||||||
|
->addColumn('idvariant', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idproduct', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('label', 'string', ['limit' => 100, 'comment' => 'es. 8 lezioni'])
|
||||||
|
->addColumn('lessons', 'integer', ['null' => true, 'comment' => 'NULL = illimitate'])
|
||||||
|
->addColumn('validity_mode', 'string', ['limit' => 20, 'default' => 'duration', 'comment' => 'duration|calendar_year|season|none'])
|
||||||
|
->addColumn('validity_value', 'integer', ['null' => true])
|
||||||
|
->addColumn('validity_unit', 'string', ['limit' => 10, 'null' => true, 'comment' => 'days|weeks|months'])
|
||||||
|
->addColumn('validity_start', 'string', ['limit' => 20, 'default' => 'first_lesson', 'comment' => 'purchase|first_lesson'])
|
||||||
|
->addColumn('price', 'decimal', ['precision' => 8, 'scale' => 2, 'default' => 0])
|
||||||
|
->addColumn('compare_price', 'decimal', ['precision' => 8, 'scale' => 2, 'null' => true, 'comment' => 'prezzo barrato'])
|
||||||
|
->addColumn('price_note', 'string', ['limit' => 100, 'null' => true, 'comment' => 'es. circa 9 euro a lezione'])
|
||||||
|
->addColumn('target_idvariant', 'integer', ['signed' => false, 'null' => true, 'comment' => 'buono regalo: variante regalata'])
|
||||||
|
->addColumn('wc_product_id', 'integer', ['null' => true])
|
||||||
|
->addColumn('wc_variation_id', 'integer', ['null' => true])
|
||||||
|
->addColumn('active', 'string', ['limit' => 1, 'default' => 'Y'])
|
||||||
|
->addColumn('sort_order', 'integer', ['default' => 0])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool'], ['name' => 'product_variants_idschool'])
|
||||||
|
->addIndex(['wc_product_id', 'wc_variation_id'], ['name' => 'product_variants_wc'])
|
||||||
|
->addForeignKey('idproduct', 'products', 'idproduct', self::CASCADE)
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->table('product_variants')
|
||||||
|
->addForeignKey('target_idvariant', 'product_variants', 'idvariant', self::SETNULL)
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// product_services: su quali classi / categorie vale il prodotto
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('product_services', self::OPT + ['primary_key' => ['idproductservice']])
|
||||||
|
->addColumn('idproductservice', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idproduct', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idservice', 'integer', ['null' => true])
|
||||||
|
->addColumn('idservicecategory', 'integer', ['null' => true])
|
||||||
|
->addIndex(['idschool'], ['name' => 'product_services_idschool'])
|
||||||
|
->addIndex(['idservice'], ['name' => 'product_services_idservice'])
|
||||||
|
->addForeignKey('idproduct', 'products', 'idproduct', self::CASCADE)
|
||||||
|
->addForeignKey('idservice', 'service', 'idservice', self::CASCADE)
|
||||||
|
->addForeignKey('idservicecategory', 'servicecategory', 'idservicecategory', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// product_images: galleria del prodotto
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('product_images', self::OPT + ['primary_key' => ['idimage']])
|
||||||
|
->addColumn('idimage', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idproduct', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('filename', 'string', ['limit' => 191])
|
||||||
|
->addColumn('sort_order', 'integer', ['default' => 0])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool'], ['name' => 'product_images_idschool'])
|
||||||
|
->addForeignKey('idproduct', 'products', 'idproduct', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// orderbook_services: le 1-2 classi scelte nei pacchetti fissi
|
||||||
|
// (nessuna FK verso service, come bookingclass -> serviceschedule)
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('orderbook_services', self::OPT + ['primary_key' => ['idorderbookservice']])
|
||||||
|
->addColumn('idorderbookservice', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idorderbook', 'integer')
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idservice', 'integer')
|
||||||
|
->addColumn('slot', 'integer', ['default' => 1, 'comment' => '1 = prima classe, 2 = seconda (bisettimanale)'])
|
||||||
|
->addIndex(['idorderbook', 'slot'], ['unique' => true, 'name' => 'orderbook_services_order_slot'])
|
||||||
|
->addIndex(['idschool', 'idservice'], ['name' => 'orderbook_services_school_service'])
|
||||||
|
->addForeignKey('idorderbook', 'orderbook', 'idorderbook', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// memberships: tessere / quota associativa
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('memberships', self::OPT + ['primary_key' => ['idmembership']])
|
||||||
|
->addColumn('idmembership', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('iduser', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idorderbook', 'integer', ['null' => true, 'comment' => 'pacchetto di origine'])
|
||||||
|
->addColumn('card_number', 'string', ['limit' => 50, 'null' => true])
|
||||||
|
->addColumn('valid_from', 'date')
|
||||||
|
->addColumn('valid_to', 'date')
|
||||||
|
->addColumn('status', 'string', ['limit' => 20, 'default' => 'active', 'comment' => 'active|cancelled'])
|
||||||
|
->addColumn('notes', 'text', ['null' => true])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool', 'iduser', 'valid_to'], ['name' => 'memberships_school_user_valid'])
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', self::CASCADE)
|
||||||
|
->addForeignKey('iduser', 'auth_users', 'id', self::CASCADE)
|
||||||
|
->addForeignKey('idorderbook', 'orderbook', 'idorderbook', self::SETNULL)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// gift_vouchers: buoni regalo (regalano una variante precisa)
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('gift_vouchers', self::OPT + ['primary_key' => ['idvoucher']])
|
||||||
|
->addColumn('idvoucher', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('code', 'string', ['limit' => 32])
|
||||||
|
->addColumn('idvariant', 'integer', ['signed' => false, 'comment' => 'variante regalata'])
|
||||||
|
->addColumn('buyer_iduser', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('buyer_name', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('buyer_email', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('recipient_name', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('recipient_email', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('message', 'text', ['null' => true])
|
||||||
|
->addColumn('source', 'string', ['limit' => 20, 'null' => true, 'comment' => 'manual|stripe|bank|woocommerce'])
|
||||||
|
->addColumn('amount', 'decimal', ['precision' => 8, 'scale' => 2, 'null' => true])
|
||||||
|
->addColumn('expires_at', 'date', ['null' => true])
|
||||||
|
->addColumn('status', 'string', ['limit' => 20, 'default' => 'active', 'comment' => 'active|redeemed|cancelled|expired'])
|
||||||
|
->addColumn('redeemed_by', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('redeemed_at', 'datetime', ['null' => true])
|
||||||
|
->addColumn('redeemed_idorderbook', 'integer', ['null' => true])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool', 'code'], ['unique' => true, 'name' => 'gift_vouchers_school_code'])
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', self::CASCADE)
|
||||||
|
->addForeignKey('idvariant', 'product_variants', 'idvariant', self::RESTRICT)
|
||||||
|
->addForeignKey('buyer_iduser', 'auth_users', 'id', self::SETNULL)
|
||||||
|
->addForeignKey('redeemed_by', 'auth_users', 'id', self::SETNULL)
|
||||||
|
->addForeignKey('redeemed_idorderbook', 'orderbook', 'idorderbook', self::SETNULL)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// coupons
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('coupons', self::OPT + ['primary_key' => ['idcoupon']])
|
||||||
|
->addColumn('idcoupon', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('code', 'string', ['limit' => 40])
|
||||||
|
->addColumn('description', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('discount_type', 'string', ['limit' => 10, 'default' => 'percent', 'comment' => 'percent|fixed'])
|
||||||
|
->addColumn('discount_value', 'decimal', ['precision' => 8, 'scale' => 2, 'default' => 0])
|
||||||
|
->addColumn('valid_from', 'date', ['null' => true])
|
||||||
|
->addColumn('valid_to', 'date', ['null' => true])
|
||||||
|
->addColumn('max_uses', 'integer', ['null' => true, 'comment' => 'NULL = illimitati'])
|
||||||
|
->addColumn('max_uses_per_user', 'integer', ['null' => true, 'default' => 1])
|
||||||
|
->addColumn('min_amount', 'decimal', ['precision' => 8, 'scale' => 2, 'null' => true])
|
||||||
|
->addColumn('new_students_only', 'string', ['limit' => 1, 'default' => 'N'])
|
||||||
|
->addColumn('active', 'string', ['limit' => 1, 'default' => 'Y'])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool', 'code'], ['unique' => true, 'name' => 'coupons_school_code'])
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->table('coupon_products', self::OPT + ['primary_key' => ['idcouponproduct']])
|
||||||
|
->addColumn('idcouponproduct', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idcoupon', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idproduct', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('idvariant', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addIndex(['idschool'], ['name' => 'coupon_products_idschool'])
|
||||||
|
->addForeignKey('idcoupon', 'coupons', 'idcoupon', self::CASCADE)
|
||||||
|
->addForeignKey('idproduct', 'products', 'idproduct', self::CASCADE)
|
||||||
|
->addForeignKey('idvariant', 'product_variants', 'idvariant', self::CASCADE)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->table('coupon_redemptions', self::OPT + ['primary_key' => ['idredemption']])
|
||||||
|
->addColumn('idredemption', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('idcoupon', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('iduser', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('idorderbook', 'integer', ['null' => true])
|
||||||
|
->addColumn('discount_amount', 'decimal', ['precision' => 8, 'scale' => 2, 'default' => 0])
|
||||||
|
->addColumn('redeemed_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['idschool'], ['name' => 'coupon_redemptions_idschool'])
|
||||||
|
->addIndex(['idcoupon', 'iduser'], ['name' => 'coupon_redemptions_coupon_user'])
|
||||||
|
->addForeignKey('idcoupon', 'coupons', 'idcoupon', self::RESTRICT)
|
||||||
|
->addForeignKey('iduser', 'auth_users', 'id', self::SETNULL)
|
||||||
|
->addForeignKey('idorderbook', 'orderbook', 'idorderbook', self::SETNULL)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// orderbook: collegamento al prodotto + copia delle regole + pagamento
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('orderbook')
|
||||||
|
->addColumn('idproduct', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('idvariant', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('booking_mode', 'string', ['limit' => 10, 'null' => true, 'comment' => 'fixed|free|single (copia)'])
|
||||||
|
->addColumn('weekly_limit', 'integer', ['null' => true, 'comment' => 'copia dal prodotto'])
|
||||||
|
->addColumn('rules_snapshot', 'text', ['null' => true, 'comment' => 'JSON: regole al momento dell acquisto'])
|
||||||
|
->addColumn('source', 'string', ['limit' => 20, 'null' => true, 'comment' => 'woocommerce|manual|stripe|bank|voucher; NULL = storico'])
|
||||||
|
->addColumn('payment_status', 'string', ['limit' => 20, 'null' => true, 'comment' => 'paid|pending|refunded'])
|
||||||
|
->addColumn('amount', 'decimal', ['precision' => 8, 'scale' => 2, 'null' => true])
|
||||||
|
->addColumn('discount_amount', 'decimal', ['precision' => 8, 'scale' => 2, 'null' => true])
|
||||||
|
->addColumn('idcoupon', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addIndex(['idschool', 'idproduct'], ['name' => 'orderbook_school_product'])
|
||||||
|
->addForeignKey('idproduct', 'products', 'idproduct', self::SETNULL)
|
||||||
|
->addForeignKey('idvariant', 'product_variants', 'idvariant', self::SETNULL)
|
||||||
|
->addForeignKey('idcoupon', 'coupons', 'idcoupon', self::SETNULL)
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// option: impostazioni tessera per scuola
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
$this->table('option')
|
||||||
|
->addColumn('membership_required', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = tessera valida obbligatoria per prenotare'])
|
||||||
|
->addColumn('membership_season_start', 'integer', ['default' => 9, 'comment' => 'mese di inizio anno sportivo (1-12)'])
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->removeColumn('membership_required')
|
||||||
|
->removeColumn('membership_season_start')
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('orderbook')
|
||||||
|
->dropForeignKey('idproduct')
|
||||||
|
->dropForeignKey('idvariant')
|
||||||
|
->dropForeignKey('idcoupon')
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('orderbook')
|
||||||
|
->removeIndexByName('orderbook_school_product')
|
||||||
|
->removeColumn('idproduct')
|
||||||
|
->removeColumn('idvariant')
|
||||||
|
->removeColumn('booking_mode')
|
||||||
|
->removeColumn('weekly_limit')
|
||||||
|
->removeColumn('rules_snapshot')
|
||||||
|
->removeColumn('source')
|
||||||
|
->removeColumn('payment_status')
|
||||||
|
->removeColumn('amount')
|
||||||
|
->removeColumn('discount_amount')
|
||||||
|
->removeColumn('idcoupon')
|
||||||
|
->update();
|
||||||
|
|
||||||
|
foreach (
|
||||||
|
[
|
||||||
|
'coupon_redemptions',
|
||||||
|
'coupon_products',
|
||||||
|
'coupons',
|
||||||
|
'gift_vouchers',
|
||||||
|
'memberships',
|
||||||
|
'orderbook_services',
|
||||||
|
'product_images',
|
||||||
|
'product_services',
|
||||||
|
] as $t
|
||||||
|
) {
|
||||||
|
$this->table($t)->drop()->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->table('product_variants')->dropForeignKey('target_idvariant')->update();
|
||||||
|
$this->table('product_variants')->drop()->save();
|
||||||
|
$this->table('products')->drop()->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Impostazioni del negozio per scuola (riga `option`):
|
||||||
|
* attivazione, Stripe Connect (solo ID account e stato), bonifico, condizioni di acquisto.
|
||||||
|
* Le chiavi Stripe della piattaforma restano nel .env, mai nel database.
|
||||||
|
*/
|
||||||
|
final class AddShopSettingsToOption extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->addColumn('shop_enabled', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = negozio YogiBook attivo per le allieve'])
|
||||||
|
->addColumn('stripe_account_id', 'string', ['limit' => 64, 'null' => true, 'comment' => 'Stripe Connect: acct_...'])
|
||||||
|
->addColumn('stripe_charges_enabled', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = Stripe accetta pagamenti per questo account'])
|
||||||
|
->addColumn('stripe_connected_at', 'datetime', ['null' => true])
|
||||||
|
->addColumn('bank_enabled', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = pagamento con bonifico'])
|
||||||
|
->addColumn('bank_holder', 'string', ['limit' => 191, 'null' => true, 'comment' => 'intestatario del conto'])
|
||||||
|
->addColumn('bank_iban', 'string', ['limit' => 34, 'null' => true])
|
||||||
|
->addColumn('bank_name', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('bank_reference', 'string', ['limit' => 191, 'null' => true, 'comment' => 'causale con {ordine} e {nome}'])
|
||||||
|
->addColumn('bank_due_days', 'integer', ['default' => 5, 'comment' => 'giorni entro cui pagare'])
|
||||||
|
->addColumn('shop_terms_text', 'text', ['null' => true, 'comment' => 'condizioni di acquisto'])
|
||||||
|
->addColumn('shop_terms_url', 'string', ['limit' => 255, 'null' => true, 'comment' => 'oppure link alle condizioni'])
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->removeColumn('shop_enabled')
|
||||||
|
->removeColumn('stripe_account_id')
|
||||||
|
->removeColumn('stripe_charges_enabled')
|
||||||
|
->removeColumn('stripe_connected_at')
|
||||||
|
->removeColumn('bank_enabled')
|
||||||
|
->removeColumn('bank_holder')
|
||||||
|
->removeColumn('bank_iban')
|
||||||
|
->removeColumn('bank_name')
|
||||||
|
->removeColumn('bank_reference')
|
||||||
|
->removeColumn('bank_due_days')
|
||||||
|
->removeColumn('shop_terms_text')
|
||||||
|
->removeColumn('shop_terms_url')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abbonamento delle scuole al portale YogiBook:
|
||||||
|
* platform_plans -> piani (prezzo mensile/annuale, limiti)
|
||||||
|
* platform_orders -> ordini di rinnovo (carta Stripe, bonifico, manuale)
|
||||||
|
* platform_settings -> impostazioni del superadmin (chiave/valore)
|
||||||
|
* schools -> piano, ciclo, prova, pagato fino al, esente
|
||||||
|
* Le chiavi Stripe della piattaforma restano nel .env.
|
||||||
|
*/
|
||||||
|
final class CreatePlatformBilling extends AbstractMigration
|
||||||
|
{
|
||||||
|
private const OPT = [
|
||||||
|
'id' => false,
|
||||||
|
'engine' => 'InnoDB',
|
||||||
|
'encoding' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->table('platform_plans', self::OPT + ['primary_key' => ['idplan']])
|
||||||
|
->addColumn('idplan', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('name', 'string', ['limit' => 100])
|
||||||
|
->addColumn('description', 'string', ['limit' => 255, 'null' => true])
|
||||||
|
->addColumn('features', 'text', ['null' => true, 'comment' => 'una caratteristica per riga'])
|
||||||
|
->addColumn('max_students', 'integer', ['null' => true, 'comment' => 'NULL = illimitati'])
|
||||||
|
->addColumn('price_month', 'decimal', ['precision' => 10, 'scale' => 2, 'null' => true, 'comment' => 'IVA esclusa; NULL = non disponibile'])
|
||||||
|
->addColumn('price_year', 'decimal', ['precision' => 10, 'scale' => 2, 'null' => true, 'comment' => 'IVA esclusa; NULL = non disponibile'])
|
||||||
|
->addColumn('highlight', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = piano consigliato'])
|
||||||
|
->addColumn('active', 'string', ['limit' => 1, 'default' => 'Y'])
|
||||||
|
->addColumn('sort_order', 'integer', ['default' => 0])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->table('schools')
|
||||||
|
->addColumn('idplan', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('billing_cycle', 'string', ['limit' => 10, 'default' => 'year', 'comment' => 'month|year'])
|
||||||
|
->addColumn('trial_until', 'date', ['null' => true])
|
||||||
|
->addColumn('paid_until', 'date', ['null' => true])
|
||||||
|
->addColumn('billing_exempt', 'string', ['limit' => 1, 'default' => 'N', 'comment' => 'Y = non paga (es. scuola interna)'])
|
||||||
|
->addColumn('billing_email', 'string', ['limit' => 191, 'null' => true, 'comment' => 'email per ricevute e avvisi di rinnovo'])
|
||||||
|
->addForeignKey('idplan', 'platform_plans', 'idplan', ['delete' => 'SET_NULL', 'update' => 'NO_ACTION'])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('platform_orders', self::OPT + ['primary_key' => ['idorder']])
|
||||||
|
->addColumn('idorder', 'integer', ['signed' => false, 'identity' => true])
|
||||||
|
->addColumn('number', 'string', ['limit' => 20, 'null' => true, 'comment' => 'YB-AAAA-00000'])
|
||||||
|
->addColumn('idschool', 'integer', ['signed' => false])
|
||||||
|
->addColumn('idplan', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('plan_name', 'string', ['limit' => 100])
|
||||||
|
->addColumn('cycle', 'string', ['limit' => 10, 'comment' => 'month|year'])
|
||||||
|
->addColumn('period_from', 'date', ['null' => true, 'comment' => 'definitivo al pagamento'])
|
||||||
|
->addColumn('period_to', 'date', ['null' => true])
|
||||||
|
->addColumn('amount_net', 'decimal', ['precision' => 10, 'scale' => 2])
|
||||||
|
->addColumn('vat_rate', 'decimal', ['precision' => 5, 'scale' => 2, 'default' => 0])
|
||||||
|
->addColumn('vat_amount', 'decimal', ['precision' => 10, 'scale' => 2, 'default' => 0])
|
||||||
|
->addColumn('total', 'decimal', ['precision' => 10, 'scale' => 2])
|
||||||
|
->addColumn('currency', 'string', ['limit' => 3, 'default' => 'EUR'])
|
||||||
|
->addColumn('method', 'string', ['limit' => 10, 'comment' => 'stripe|bank|manual'])
|
||||||
|
->addColumn('status', 'string', ['limit' => 12, 'default' => 'pending', 'comment' => 'pending|paid|cancelled|refunded'])
|
||||||
|
->addColumn('stripe_session_id', 'string', ['limit' => 255, 'null' => true])
|
||||||
|
->addColumn('stripe_payment_intent', 'string', ['limit' => 255, 'null' => true])
|
||||||
|
->addColumn('bank_reference', 'string', ['limit' => 191, 'null' => true])
|
||||||
|
->addColumn('due_date', 'date', ['null' => true, 'comment' => 'bonifico: pagare entro'])
|
||||||
|
->addColumn('billing_snapshot', 'text', ['null' => true, 'comment' => 'JSON dati fiscali della scuola al momento dell ordine'])
|
||||||
|
->addColumn('notes', 'text', ['null' => true])
|
||||||
|
->addColumn('created_by', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('confirmed_by', 'integer', ['signed' => false, 'null' => true])
|
||||||
|
->addColumn('paid_at', 'datetime', ['null' => true])
|
||||||
|
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->addIndex(['number'], ['unique' => true, 'name' => 'platform_orders_number'])
|
||||||
|
->addIndex(['idschool', 'status'], ['name' => 'platform_orders_school_status'])
|
||||||
|
->addIndex(['stripe_session_id'], ['name' => 'platform_orders_stripe_session'])
|
||||||
|
->addForeignKey('idschool', 'schools', 'idschool', ['delete' => 'RESTRICT', 'update' => 'NO_ACTION'])
|
||||||
|
->addForeignKey('idplan', 'platform_plans', 'idplan', ['delete' => 'SET_NULL', 'update' => 'NO_ACTION'])
|
||||||
|
->addForeignKey('created_by', 'auth_users', 'id', ['delete' => 'SET_NULL', 'update' => 'NO_ACTION'])
|
||||||
|
->addForeignKey('confirmed_by', 'auth_users', 'id', ['delete' => 'SET_NULL', 'update' => 'NO_ACTION'])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->table('platform_settings', self::OPT + ['primary_key' => ['setting_key']])
|
||||||
|
->addColumn('setting_key', 'string', ['limit' => 64])
|
||||||
|
->addColumn('setting_value', 'text', ['null' => true])
|
||||||
|
->addColumn('updated_at', 'timestamp', ['null' => true, 'default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP'])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('platform_settings')->drop()->save();
|
||||||
|
$this->table('platform_orders')->drop()->save();
|
||||||
|
|
||||||
|
$this->table('schools')->dropForeignKey('idplan')->update();
|
||||||
|
$this->table('schools')
|
||||||
|
->removeColumn('idplan')
|
||||||
|
->removeColumn('billing_cycle')
|
||||||
|
->removeColumn('trial_until')
|
||||||
|
->removeColumn('paid_until')
|
||||||
|
->removeColumn('billing_exempt')
|
||||||
|
->removeColumn('billing_email')
|
||||||
|
->update();
|
||||||
|
|
||||||
|
$this->table('platform_plans')->drop()->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Percorso "Primi passi" della scuola:
|
||||||
|
* setup_state JSON con i passi segnati a mano / saltati e l'ultimo avanzamento
|
||||||
|
* setup_completed_at quando l'owner ha chiuso il percorso (nasconde il promemoria)
|
||||||
|
* Le scuole già in uso (es. Seregno) vengono segnate come completate.
|
||||||
|
*/
|
||||||
|
final class AddSetupStateToOption extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->addColumn('setup_state', 'text', ['null' => true, 'comment' => 'JSON percorso Primi passi'])
|
||||||
|
->addColumn('setup_completed_at', 'datetime', ['null' => true])
|
||||||
|
->update();
|
||||||
|
|
||||||
|
// Scuole che hanno già ordini o prenotazioni: percorso considerato concluso
|
||||||
|
$this->execute(
|
||||||
|
"UPDATE `option` o SET o.setup_completed_at = NOW()
|
||||||
|
WHERE EXISTS (SELECT 1 FROM orderbook ob WHERE ob.idschool = o.idschool)
|
||||||
|
OR EXISTS (SELECT 1 FROM bookingclass b WHERE b.idschool = o.idschool)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
$this->table('option')
|
||||||
|
->removeColumn('setup_state')
|
||||||
|
->removeColumn('setup_completed_at')
|
||||||
|
->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,106 +1,76 @@
|
|||||||
<?php
|
<?php
|
||||||
// Connessione al database (adattare le informazioni di connessione)
|
require_once('include/headscript.php');
|
||||||
include('include/headscript.php');
|
SchoolContext::requireStaff();
|
||||||
require_once __DIR__ . '/class/mailer.php';
|
require_once('class/SchoolMail.php');
|
||||||
|
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
/**
|
||||||
use PHPMailer\PHPMailer\Exception;
|
* Accetta una prenotazione "pending" della scuola corrente (pendingbookedclass.php).
|
||||||
|
* - richiesta di riprogrammazione (prevbookingstart valorizzato): booked + is_reprogrammed = 'Y'
|
||||||
|
* - nuova prenotazione da confermare: booked, is_reprogrammed invariato
|
||||||
|
* Poi avvisa l'allievo via email (SchoolMail, a nome della scuola).
|
||||||
|
*/
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
$conn = $bkngstm; // riusa la connessione già aperta da bkngstm.php
|
$idbookingclass = (int) ($_GET['idbookingclass'] ?? 0);
|
||||||
|
if ($idbookingclass <= 0 || !SchoolScope::belongs('bookingclass', $idbookingclass)) {
|
||||||
// Recupera il parametro "idbookingclass" dalla richiesta GET
|
header('Location: pendingbookedclass.php?message=error');
|
||||||
|
exit();
|
||||||
// Recupera il parametro "idbookingclass" dalla richiesta GET
|
|
||||||
if (isset($_GET['idbookingclass'])) {
|
|
||||||
$idbookingclass = (int) $_GET['idbookingclass'];
|
|
||||||
|
|
||||||
// Aggiorna lo status a "booked" e is_reprogrammed a "Y" nella tabella "bookingclass"
|
|
||||||
$query = "UPDATE bookingclass SET status = 'booked', is_reprogrammed = 'Y' WHERE idbookingclass = ?";
|
|
||||||
$stmt = $conn->prepare($query);
|
|
||||||
|
|
||||||
if ($stmt) {
|
|
||||||
$stmt->bind_param("i", $idbookingclass);
|
|
||||||
if ($stmt->execute()) {
|
|
||||||
// Query per recuperare i dettagli della prenotazione
|
|
||||||
$query = "SELECT bookingclass.*, auth_users.*, service.*
|
|
||||||
FROM bookingclass
|
|
||||||
LEFT JOIN auth_users ON bookingclass.iduser = auth_users.id
|
|
||||||
LEFT JOIN service ON bookingclass.idservice = service.idservice
|
|
||||||
WHERE bookingclass.idbookingclass = $idbookingclass";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
|
|
||||||
if ($result) {
|
|
||||||
// Elabora i risultati
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
// Ora puoi accedere ai dati delle tabelle
|
|
||||||
$newtime = $row['bookingstart'];
|
|
||||||
$emailuser = $row['email'];
|
|
||||||
$firstname = $row['first_name'];
|
|
||||||
|
|
||||||
$newtimeformat = date("d-m-Y H:i", strtotime($newtime));
|
|
||||||
|
|
||||||
// Mail to client
|
|
||||||
$messageedit = "
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 18px; line-height: 34.2px;'><strong><span style='line-height: 34.2px; font-size: 18px;'> Ciao $firstname , </span></strong></span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>La tua richiesta di riprogrammazione è stata accettata! </span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Ecco il dettaglio della riprogrammazione $newtimeformat</span></p>
|
|
||||||
<br>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Per vedere e gestire le tue lezioni clicca qui: https://yogibook.yogasoul.it </span></p>
|
|
||||||
<br>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Se non ricordi la password o non hai sei mai entrata in Yogibbok, per prima cosa resettare la password cliccando di seguito</span></p>
|
|
||||||
<br>
|
|
||||||
<a href='https://yogibook.yogasoul.it/password/reset' target='_blank' class='v-button v-font-size' style='box-sizing: border-box;display: inline-block;text-decoration: none;-webkit-text-size-adjust: none;text-align: center;color: #FFFFFF; background-color: #3AAEE0; border-radius: 4px;-webkit-border-radius: 4px; -moz-border-radius: 4px; width:auto; max-width:100%; overflow-wrap: break-word; word-break: break-word; word-wrap:break-word; mso-border-alt: none;font-size: 14px;'>
|
|
||||||
<span style='display:block;padding:10px 20px;line-height:120%;'><span style='line-height: 16.8px;'>Reset Password</span></span>
|
|
||||||
</a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Ci vediamo sul tappetino!</span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Il Team Yogasoul</span></p>";
|
|
||||||
|
|
||||||
$buttonedit = "<a href='https://yogibook.yogasoul.it/' target='_blank' class='v-button v-font-size' style='box-sizing: border-box;display: inline-block;text-decoration: none;-webkit-text-size-adjust: none;text-align: center;color: #FFFFFF; background-color: #3AAEE0; border-radius: 4px;-webkit-border-radius: 4px; -moz-border-radius: 4px; width:auto; max-width:100%; overflow-wrap: break-word; word-break: break-word; word-wrap:break-word; mso-border-alt: none;font-size: 14px;'>
|
|
||||||
<span style='display:block;padding:10px 20px;line-height:120%;'><span style='line-height: 16.8px;'>YogiBook - YogaSoul</span></span>
|
|
||||||
</a>";
|
|
||||||
|
|
||||||
$mail = new PHPMailer(true);
|
|
||||||
|
|
||||||
$mail->isSMTP();
|
|
||||||
$mail->Host = $_ENV['MAIL_HOST'];
|
|
||||||
$mail->SMTPAuth = true;
|
|
||||||
$mail->Username = $_ENV['MAIL_USERNAME'];
|
|
||||||
$mail->Password = $_ENV['MAIL_PASSWORD'];
|
|
||||||
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION']; // ssl
|
|
||||||
$mail->Port = (int) $_ENV['MAIL_PORT']; // 465
|
|
||||||
$mail->CharSet = 'UTF-8';
|
|
||||||
|
|
||||||
include('mail/emailtemplate2.php');
|
|
||||||
// Email body content
|
|
||||||
$htmlContent = $mailmessage1;
|
|
||||||
|
|
||||||
$mail->From = $_ENV['MAIL_FROM_ADDRESS'];
|
|
||||||
$mail->FromName = $_ENV['MAIL_FROM_NAME'];
|
|
||||||
$mail->addAddress($emailuser); // Add a recipient
|
|
||||||
|
|
||||||
$mail->Subject = "YogiBook - Lezione riprogrammata con successo!";
|
|
||||||
$mail->Body = $htmlContent;
|
|
||||||
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
|
|
||||||
|
|
||||||
$mail->send();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reindirizza alla pagina "pendingbookedclass.php" dopo l'aggiornamento
|
|
||||||
header("Location: pendingbookedclass.php");
|
|
||||||
exit(); // Assicura che il codice successivo non venga eseguito dopo il reindirizzamento
|
|
||||||
} else {
|
|
||||||
echo "Errore durante l'esecuzione della query: " . $conn->error;
|
|
||||||
}
|
|
||||||
$stmt->close();
|
|
||||||
} else {
|
|
||||||
echo "Errore durante l'esecuzione della query: " . $stmt->error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo "Errore nella preparazione della query: " . $conn->error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo "Parametro 'idbookingclass' non trovato nella richiesta GET.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT bc.bookingstart, bc.prevbookingstart, u.email, u.first_name, s.servicename
|
||||||
|
FROM bookingclass bc
|
||||||
|
LEFT JOIN auth_users u ON u.id = bc.iduser
|
||||||
|
LEFT JOIN service s ON s.idservice = bc.idservice AND s.idschool = bc.idschool
|
||||||
|
WHERE bc.idbookingclass = ? AND bc.idschool = ? AND bc.status = 'pending'"
|
||||||
|
);
|
||||||
|
$st->execute([$idbookingclass, $idschool]);
|
||||||
|
$row = $st->fetch();
|
||||||
|
if (!$row) {
|
||||||
|
header('Location: pendingbookedclass.php?message=notpending');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$isReprogram = !empty($row['prevbookingstart']);
|
||||||
|
|
||||||
|
$upd = $pdo->prepare(
|
||||||
|
"UPDATE bookingclass
|
||||||
|
SET status = 'booked',
|
||||||
|
is_reprogrammed = IF(? = 1, 'Y', is_reprogrammed)
|
||||||
|
WHERE idbookingclass = ? AND idschool = ? AND status = 'pending'"
|
||||||
|
);
|
||||||
|
$upd->execute([$isReprogram ? 1 : 0, $idbookingclass, $idschool]);
|
||||||
|
|
||||||
|
if ($upd->rowCount() === 0) {
|
||||||
|
header('Location: pendingbookedclass.php?message=notpending');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} catch (PDOException $ex) {
|
||||||
|
error_log('[acceptbookingclass] ' . $ex->getMessage());
|
||||||
|
header('Location: pendingbookedclass.php?message=error');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email all'allievo (best-effort: SchoolMail registra l'errore e ritorna false)
|
||||||
|
$h = fn($v) => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
|
||||||
|
$when = $row['bookingstart'] ? date('d-m-Y H:i', strtotime($row['bookingstart'])) : '';
|
||||||
|
$lesson = '<strong>' . $h($row['servicename'] ?? '') . '</strong>' . ($when !== '' ? ' – ' . $h($when) : '');
|
||||||
|
|
||||||
|
if ($isReprogram) {
|
||||||
|
$subject = 'Lezione riprogrammata con successo';
|
||||||
|
$lines = [
|
||||||
|
'La tua richiesta di riprogrammazione è stata <strong>accettata</strong>!',
|
||||||
|
'Nuova lezione: ' . $lesson,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$subject = 'Prenotazione confermata';
|
||||||
|
$lines = [
|
||||||
|
'La tua prenotazione è stata <strong>confermata</strong>!',
|
||||||
|
'Lezione: ' . $lesson,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
SchoolMail::toStudent((string) ($row['email'] ?? ''), (string) ($row['first_name'] ?? ''), $subject, $lines);
|
||||||
|
|
||||||
|
header('Location: pendingbookedclass.php?message=accepted');
|
||||||
|
exit();
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connessione unica PDO (singleton).
|
* Catalogo classi (service) della scuola corrente:
|
||||||
|
* inserimento, assegnazione insegnante, propagazione sul calendario.
|
||||||
*/
|
*/
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
function e($value): string
|
function e($value): string
|
||||||
@@ -27,13 +29,16 @@ $message = $_GET['message'] ?? 'N';
|
|||||||
$insertFeedback = null;
|
$insertFeedback = null;
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* Insegnanti (titolare per primo, poi attivi, poi alfabetico)
|
* Insegnanti della scuola (titolare per primo, poi attivi, poi alfabetico)
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
$teachers = $pdo->query(
|
$st = $pdo->prepare(
|
||||||
"SELECT idemployee, nameemployee, surnameemployee, photo, is_owner, active
|
"SELECT idemployee, nameemployee, surnameemployee, photo, is_owner, active
|
||||||
FROM employee
|
FROM employee
|
||||||
ORDER BY is_owner DESC, active DESC, surnameemployee, nameemployee"
|
WHERE idschool = ?
|
||||||
)->fetchAll();
|
ORDER BY is_owner DESC, active DESC, surnameemployee, nameemployee"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$teachers = $st->fetchAll();
|
||||||
|
|
||||||
$teachersById = [];
|
$teachersById = [];
|
||||||
$ownerId = 0;
|
$ownerId = 0;
|
||||||
@@ -51,55 +56,122 @@ if (($_POST['action'] ?? '') === 'assignteacher') {
|
|||||||
$idservice = (int) ($_POST['idservice'] ?? 0);
|
$idservice = (int) ($_POST['idservice'] ?? 0);
|
||||||
$idteacher = (int) ($_POST['idteacher'] ?? 0);
|
$idteacher = (int) ($_POST['idteacher'] ?? 0);
|
||||||
|
|
||||||
if ($idservice > 0 && isset($teachersById[$idteacher])) {
|
if (SchoolScope::belongs('service', $idservice) && isset($teachersById[$idteacher])) {
|
||||||
$stmt = $pdo->prepare("UPDATE service SET idteacher = :t WHERE idservice = :s");
|
$pdo->prepare("UPDATE service SET idteacher = ? WHERE idservice = ? AND idschool = ?")
|
||||||
$stmt->execute([':t' => $idteacher, ':s' => $idservice]);
|
->execute([$idteacher, $idservice, $idschool]);
|
||||||
header('Location: ' . $_SERVER['PHP_SELF'] . '?message=teacherassigned');
|
header('Location: admin-services.php?message=teacherassigned');
|
||||||
} else {
|
} else {
|
||||||
header('Location: ' . $_SERVER['PHP_SELF'] . '?message=teachererror');
|
header('Location: admin-services.php?message=teachererror');
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* Inserimento nuova classe (POST) con prepared statement
|
* Gestione categorie (POST): aggiungi / rinomina / elimina
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
if (isset($_POST['classinsert']) && $_POST['classinsert'] === 'Y') {
|
$catAction = $_POST['cataction'] ?? '';
|
||||||
$servicename = trim($_POST['servicename'] ?? '');
|
if ($catAction !== '') {
|
||||||
$wpcatalog = $_POST['wpcatalognumber'] ?? '';
|
$catName = trim((string) ($_POST['namecategory'] ?? ''));
|
||||||
$day = trim($_POST['classdayday'] ?? '');
|
$catId = (int) ($_POST['idservicecategory'] ?? 0);
|
||||||
$time = trim($_POST['classtime'] ?? '');
|
$nameOk = $catName !== '' && mb_strlen($catName) <= 50;
|
||||||
$category = $_POST['servicecategory'] ?? '';
|
|
||||||
$maxcapacity = $_POST['maxcapacity'] ?? '';
|
if (in_array($catAction, ['add', 'rename'], true)) {
|
||||||
$colorclass = trim($_POST['colorclass'] ?? '');
|
if (!$nameOk) {
|
||||||
$classduration = $_POST['classduration'] ?? '';
|
header('Location: admin-services.php?message=catinvalid');
|
||||||
$idteacher = (int) ($_POST['idteacher'] ?? 0);
|
exit;
|
||||||
|
}
|
||||||
|
$dup = $pdo->prepare("SELECT COUNT(*) FROM servicecategory WHERE idschool = ? AND namecategory = ? AND idservicecategory <> ?");
|
||||||
|
$dup->execute([$idschool, $catName, $catId]);
|
||||||
|
if ((int) $dup->fetchColumn() > 0) {
|
||||||
|
header('Location: admin-services.php?message=catdup');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($catAction === 'add') {
|
||||||
|
$pdo->prepare("INSERT INTO servicecategory (idschool, namecategory) VALUES (?, ?)")->execute([$idschool, $catName]);
|
||||||
|
header('Location: admin-services.php?message=catadded');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($catAction === 'rename' && SchoolScope::belongs('servicecategory', $catId)) {
|
||||||
|
$pdo->prepare("UPDATE servicecategory SET namecategory = ? WHERE idservicecategory = ? AND idschool = ?")
|
||||||
|
->execute([$catName, $catId, $idschool]);
|
||||||
|
header('Location: admin-services.php?message=catrenamed');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($catAction === 'delete' && SchoolScope::belongs('servicecategory', $catId)) {
|
||||||
|
$used = $pdo->prepare("SELECT COUNT(*) FROM service WHERE category = ? AND idschool = ?");
|
||||||
|
$used->execute([$catId, $idschool]);
|
||||||
|
if ((int) $used->fetchColumn() > 0) {
|
||||||
|
header('Location: admin-services.php?message=catinuse');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$pdo->prepare("DELETE FROM servicecategory WHERE idservicecategory = ? AND idschool = ?")->execute([$catId, $idschool]);
|
||||||
|
header('Location: admin-services.php?message=catdeleted');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
header('Location: admin-services.php?message=notfound');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* Categorie della scuola (servono anche per validare l'inserimento)
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
$st = $pdo->prepare("SELECT idservicecategory, namecategory FROM servicecategory WHERE idschool = ? ORDER BY namecategory");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$categories = $st->fetchAll();
|
||||||
|
$categoryIds = array_map('intval', array_column($categories, 'idservicecategory'));
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT category, COUNT(*) AS n FROM service WHERE idschool = ? GROUP BY category");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$catUsage = array_column($st->fetchAll(), 'n', 'category');
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------
|
||||||
|
* Inserimento nuova classe (POST)
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
if (($_POST['classinsert'] ?? '') === 'Y') {
|
||||||
|
$servicename = trim($_POST['servicename'] ?? '');
|
||||||
|
$wpcatalog = preg_replace('/[^0-9,]/', '', (string) ($_POST['wpcatalognumber'] ?? ''));
|
||||||
|
$day = trim($_POST['classdayday'] ?? '');
|
||||||
|
$time = trim($_POST['classtime'] ?? '');
|
||||||
|
$category = (int) ($_POST['servicecategory'] ?? 0);
|
||||||
|
$maxcapacity = trim((string) ($_POST['maxcapacity'] ?? ''));
|
||||||
|
$colorclass = trim($_POST['colorclass'] ?? '');
|
||||||
|
$classduration = str_replace(',', '.', trim((string) ($_POST['classduration'] ?? '')));
|
||||||
|
$idteacher = (int) ($_POST['idteacher'] ?? 0);
|
||||||
|
|
||||||
|
$validDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||||
|
|
||||||
if ($servicename === '') {
|
if ($servicename === '') {
|
||||||
$insertFeedback = ['type' => 'error', 'text' => 'La descrizione della classe è obbligatoria.'];
|
$insertFeedback = ['type' => 'error', 'text' => 'La descrizione della classe è obbligatoria.'];
|
||||||
|
} elseif (!in_array($day, $validDays, true)) {
|
||||||
|
$insertFeedback = ['type' => 'error', 'text' => 'Seleziona il giorno della classe.'];
|
||||||
|
} elseif (!preg_match('/^\d{1,2}:\d{2}$/', $time)) {
|
||||||
|
$insertFeedback = ['type' => 'error', 'text' => 'Inserisci l\'ora nel formato HH:MM (es. 18:30).'];
|
||||||
} elseif (!isset($teachersById[$idteacher])) {
|
} elseif (!isset($teachersById[$idteacher])) {
|
||||||
$insertFeedback = ['type' => 'error', 'text' => 'Seleziona l\'insegnante della classe.'];
|
$insertFeedback = ['type' => 'error', 'text' => 'Seleziona l\'insegnante della classe.'];
|
||||||
} else {
|
} else {
|
||||||
$sql = "INSERT INTO service
|
$stmt = $pdo->prepare(
|
||||||
(servicename, wpcatalognumber, day, time, category, maxcapacity, colorclass, classduration, idteacher)
|
"INSERT INTO service
|
||||||
VALUES
|
(idschool, servicename, wpcatalognumber, day, time, category, maxcapacity, colorclass, classduration, idteacher, idlocation)
|
||||||
(:servicename, :wpcatalog, :day, :time, :category, :maxcapacity, :colorclass, :classduration, :idteacher)";
|
VALUES
|
||||||
$stmt = $pdo->prepare($sql);
|
(:idschool, :servicename, :wpcatalog, :day, :time, :category, :maxcapacity, :colorclass, :classduration, :idteacher, 0)"
|
||||||
|
);
|
||||||
$ok = $stmt->execute([
|
$ok = $stmt->execute([
|
||||||
|
':idschool' => $idschool,
|
||||||
':servicename' => $servicename,
|
':servicename' => $servicename,
|
||||||
':wpcatalog' => $wpcatalog !== '' ? (int) $wpcatalog : null,
|
':wpcatalog' => $wpcatalog !== '' ? $wpcatalog : null,
|
||||||
':day' => $day,
|
':day' => $day,
|
||||||
':time' => $time,
|
':time' => $time,
|
||||||
':category' => $category !== '' ? (int) $category : null,
|
':category' => in_array($category, $categoryIds, true) ? $category : 0,
|
||||||
':maxcapacity' => $maxcapacity !== '' ? (int) $maxcapacity : null,
|
':maxcapacity' => $maxcapacity !== '' ? (int) $maxcapacity : null,
|
||||||
':colorclass' => $colorclass,
|
':colorclass' => preg_match('/^#[0-9a-fA-F]{6}$/', $colorclass) ? $colorclass : '#1ebf73',
|
||||||
':classduration' => $classduration !== '' ? (float) $classduration : null,
|
':classduration' => is_numeric($classduration) ? (float) $classduration : 1,
|
||||||
':idteacher' => $idteacher,
|
':idteacher' => $idteacher,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($ok) {
|
if ($ok) {
|
||||||
// Redirect per evitare re-invio del form al refresh (pattern PRG)
|
header('Location: admin-services.php?message=inserted');
|
||||||
header('Location: ' . $_SERVER['PHP_SELF'] . '?message=inserted');
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
$insertFeedback = ['type' => 'error', 'text' => 'Errore durante l\'inserimento della classe. Riprova.'];
|
$insertFeedback = ['type' => 'error', 'text' => 'Errore durante l\'inserimento della classe. Riprova.'];
|
||||||
@@ -107,31 +179,30 @@ if (isset($_POST['classinsert']) && $_POST['classinsert'] === 'Y') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* Categorie per il dropdown
|
* Elenco classi della scuola
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
$categories = $pdo->query("SELECT idservicecategory, namecategory FROM servicecategory ORDER BY namecategory")->fetchAll();
|
$st = $pdo->prepare(
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
|
||||||
* Elenco classi esistenti
|
|
||||||
* ---------------------------------------------------------------------- */
|
|
||||||
$services = $pdo->query(
|
|
||||||
"SELECT service.*, servicecategory.namecategory
|
"SELECT service.*, servicecategory.namecategory
|
||||||
FROM service
|
FROM service
|
||||||
LEFT JOIN servicecategory ON service.category = servicecategory.idservicecategory
|
LEFT JOIN servicecategory ON service.category = servicecategory.idservicecategory
|
||||||
ORDER BY service.servicename"
|
WHERE service.idschool = ?
|
||||||
)->fetchAll();
|
ORDER BY service.servicename"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$services = $st->fetchAll();
|
||||||
|
|
||||||
// Propagazioni già effettuate, raggruppate per servizio
|
// Propagazioni della scuola, raggruppate per servizio
|
||||||
$propagationsByService = [];
|
$propagationsByService = [];
|
||||||
$propRows = $pdo->query(
|
$st = $pdo->prepare(
|
||||||
"SELECT p.idpropagation, p.idservice, p.token, p.startdate, p.enddate, p.created_at,
|
"SELECT p.idpropagation, p.idservice, p.token, p.startdate, p.enddate, p.created_at,
|
||||||
COUNT(s.idserviceschedule) AS occorrenze
|
(SELECT COUNT(*) FROM serviceschedule s
|
||||||
FROM propagation p
|
WHERE s.propagation_token = p.token AND s.idschool = p.idschool) AS occorrenze
|
||||||
LEFT JOIN serviceschedule s ON s.propagation_token = p.token
|
FROM propagation p
|
||||||
GROUP BY p.idpropagation
|
WHERE p.idschool = ?
|
||||||
ORDER BY p.created_at DESC"
|
ORDER BY p.created_at DESC"
|
||||||
)->fetchAll();
|
);
|
||||||
foreach ($propRows as $pr) {
|
$st->execute([$idschool]);
|
||||||
|
foreach ($st->fetchAll() as $pr) {
|
||||||
$propagationsByService[$pr['idservice']][] = $pr;
|
$propagationsByService[$pr['idservice']][] = $pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +231,36 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
}
|
}
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dayLabels = [
|
||||||
|
'Monday' => 'Lunedì',
|
||||||
|
'Tuesday' => 'Martedì',
|
||||||
|
'Wednesday' => 'Mercoledì',
|
||||||
|
'Thursday' => 'Giovedì',
|
||||||
|
'Friday' => 'Venerdì',
|
||||||
|
'Saturday' => 'Sabato',
|
||||||
|
'Sunday' => 'Domenica',
|
||||||
|
];
|
||||||
|
|
||||||
|
$msgMap = [
|
||||||
|
'inserted' => ['success', 'Classe inserita con successo.'],
|
||||||
|
'updated' => ['success', 'Classe aggiornata con successo.'],
|
||||||
|
'deleted' => ['success', 'Classe eliminata con successo.'],
|
||||||
|
'teacherassigned' => ['success', 'Insegnante assegnato con successo.'],
|
||||||
|
'success' => ['success', 'Propagazione avvenuta con successo.'],
|
||||||
|
'propdeleted' => ['success', 'Propagazione eliminata con successo.'],
|
||||||
|
'teachererror' => ['danger', 'Impossibile assegnare l\'insegnante. Riprova.'],
|
||||||
|
'error' => ['danger', 'Dati non validi per la propagazione.'],
|
||||||
|
'notfound' => ['danger', 'Elemento non trovato in questa scuola.'],
|
||||||
|
'hasdata' => ['warning', 'Questa classe ha lezioni o ordini collegati e non può essere eliminata. Elimina prima le propagazioni; se ci sono ordini, la classe va mantenuta per lo storico.'],
|
||||||
|
'catadded' => ['success', 'Categoria aggiunta.'],
|
||||||
|
'catrenamed' => ['success', 'Categoria rinominata.'],
|
||||||
|
'catdeleted' => ['success', 'Categoria eliminata.'],
|
||||||
|
'catinvalid' => ['danger', 'Nome categoria obbligatorio (massimo 50 caratteri).'],
|
||||||
|
'catdup' => ['danger', 'Esiste già una categoria con questo nome.'],
|
||||||
|
'catinuse' => ['warning', 'Categoria usata da una o più classi: cambia prima la categoria di quelle classi.'],
|
||||||
|
'range' => ['danger', 'Intervallo non valido: la data di fine deve seguire l\'inizio e il periodo non può superare un anno.'],
|
||||||
|
];
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="it">
|
<html lang="it">
|
||||||
@@ -174,14 +275,15 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
|
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" /><?php include('include/schooltheme.php'); ?>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/spectrum/1.8.1/spectrum.min.css">
|
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/spectrum/1.8.1/spectrum.min.css">
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/spectrum/1.8.1/spectrum.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/spectrum/1.8.1/spectrum.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.admin-card {
|
.admin-card {
|
||||||
@@ -306,6 +408,51 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cat-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cat-chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 5px 6px 5px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cat-chip .cat-count {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 1px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cat-chip button {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: #9ca3af;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cat-chip button:hover {
|
||||||
|
color: #374151;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cat-chip button.cat-del:hover {
|
||||||
|
color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
.teacher-select.unassigned {
|
.teacher-select.unassigned {
|
||||||
border-color: #f0b27a;
|
border-color: #f0b27a;
|
||||||
background-color: #fff8f1;
|
background-color: #fff8f1;
|
||||||
@@ -328,7 +475,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<?php include('include/languageselection.php'); ?>
|
<?php include('include/schoolswitcher.php'); ?><?php include('include/languageselection.php'); ?>
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
<?php include('include/profiletopbar.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -349,25 +496,13 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
<?php if ($message === 'inserted') : ?>
|
<?php if (isset($msgMap[$message])) : ?>
|
||||||
<div class="alert alert-success" role="alert">Classe inserita con successo.</div>
|
<div class="alert alert-<?php echo $msgMap[$message][0]; ?>" role="alert"><?php echo e($msgMap[$message][1]); ?></div>
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($message === 'teacherassigned') : ?>
|
|
||||||
<div class="alert alert-success" role="alert">Insegnante assegnato con successo.</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($message === 'teachererror') : ?>
|
|
||||||
<div class="alert alert-danger" role="alert">Impossibile assegnare l'insegnante. Riprova.</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($message === 'success') : ?>
|
|
||||||
<div class="alert alert-success" role="alert">Propagazione avvenuta con successo.</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($message === 'propdeleted') : ?>
|
|
||||||
<div class="alert alert-success" role="alert">Propagazione eliminata con successo.</div>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($message === 'confirmdelete') : ?>
|
<?php if ($message === 'confirmdelete') : ?>
|
||||||
<div class="alert alert-warning" role="alert">
|
<div class="alert alert-warning" role="alert">
|
||||||
Attenzione: questa propagazione ha <strong><?php echo (int) ($_GET['count'] ?? 0); ?></strong> prenotazioni utente collegate.
|
Attenzione: questa propagazione ha <strong><?php echo (int) ($_GET['count'] ?? 0); ?></strong> prenotazioni utente collegate.
|
||||||
Vuoi eliminarla comunque insieme alle lezioni?
|
Vuoi eliminarla comunque insieme alle lezioni e alle prenotazioni?
|
||||||
<a href="cancelpropagation.php?token=<?php echo e($_GET['token'] ?? ''); ?>&confirm=Y"
|
<a href="cancelpropagation.php?token=<?php echo e($_GET['token'] ?? ''); ?>&confirm=Y"
|
||||||
class="btn btn-danger btn-sm ms-2"
|
class="btn btn-danger btn-sm ms-2"
|
||||||
onclick="return confirm('Confermi la cancellazione definitiva?');">
|
onclick="return confirm('Confermi la cancellazione definitiva?');">
|
||||||
@@ -377,9 +512,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($insertFeedback) : ?>
|
<?php if ($insertFeedback) : ?>
|
||||||
<div class="alert alert-<?php echo $insertFeedback['type'] === 'success' ? 'success' : 'danger'; ?>" role="alert">
|
<div class="alert alert-danger" role="alert"><?php echo e($insertFeedback['text']); ?></div>
|
||||||
<?php echo e($insertFeedback['text']); ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if (empty($teachers)) : ?>
|
<?php if (empty($teachers)) : ?>
|
||||||
<div class="alert alert-warning" role="alert">
|
<div class="alert alert-warning" role="alert">
|
||||||
@@ -400,28 +533,24 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="servicename" class="form-label">Descrizione classe</label>
|
<label for="servicename" class="form-label">Descrizione classe</label>
|
||||||
<input type="text" class="form-control" placeholder="Es. Hatha Yoga" id="servicename" name="servicename" required>
|
<input type="text" class="form-control" placeholder="Es. Hatha Yoga" id="servicename" name="servicename" maxlength="50" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="wpcatalognumber" class="form-label">WP catalog number</label>
|
<label for="wpcatalognumber" class="form-label">WP catalog number</label>
|
||||||
<input type="text" class="form-control" placeholder="WP Number" id="wpcatalognumber" name="wpcatalognumber">
|
<input type="text" class="form-control" placeholder="Es. 123 oppure 123,456" id="wpcatalognumber" name="wpcatalognumber">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="classdayday" class="form-label">Giorno</label>
|
<label for="classdayday" class="form-label">Giorno</label>
|
||||||
<select class="form-select" id="classdayday" name="classdayday">
|
<select class="form-select" id="classdayday" name="classdayday" required>
|
||||||
<option value="">Seleziona</option>
|
<option value="">Seleziona</option>
|
||||||
<option value="Monday">Lunedì</option>
|
<?php foreach ($dayLabels as $k => $lbl) : ?>
|
||||||
<option value="Tuesday">Martedì</option>
|
<option value="<?php echo $k; ?>"><?php echo $lbl; ?></option>
|
||||||
<option value="Wednesday">Mercoledì</option>
|
<?php endforeach; ?>
|
||||||
<option value="Thursday">Giovedì</option>
|
|
||||||
<option value="Friday">Venerdì</option>
|
|
||||||
<option value="Saturday">Sabato</option>
|
|
||||||
<option value="Sunday">Domenica</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -431,7 +560,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="classtime" class="form-label">Ora</label>
|
<label for="classtime" class="form-label">Ora</label>
|
||||||
<input type="text" class="form-control" placeholder="Es. 18:30" id="classtime" name="classtime">
|
<input type="time" class="form-control" id="classtime" name="classtime" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
@@ -446,9 +575,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<select name="servicecategory" id="servicecategory" class="form-select">
|
<select name="servicecategory" id="servicecategory" class="form-select">
|
||||||
<option value="">Seleziona</option>
|
<option value="">Seleziona</option>
|
||||||
<?php foreach ($categories as $cat) : ?>
|
<?php foreach ($categories as $cat) : ?>
|
||||||
<option value="<?php echo e($cat['idservicecategory']); ?>">
|
<option value="<?php echo (int) $cat['idservicecategory']; ?>"><?php echo e($cat['namecategory']); ?></option>
|
||||||
<?php echo e($cat['namecategory']); ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -459,7 +586,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="maxcapacity" class="form-label">Capacità massima</label>
|
<label for="maxcapacity" class="form-label">Capacità massima</label>
|
||||||
<input type="text" class="form-control" placeholder="Es. 12" id="maxcapacity" name="maxcapacity">
|
<input type="number" min="1" class="form-control" placeholder="Es. 12" id="maxcapacity" name="maxcapacity">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
@@ -485,6 +612,51 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Categorie -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card admin-card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="section-title">Categorie</div>
|
||||||
|
<p class="section-lead">Raggruppano le classi (es. Yoga, Pilates, Meditazione). Una categoria usata da qualche classe non può essere eliminata.</p>
|
||||||
|
|
||||||
|
<?php if (!empty($categories)) : ?>
|
||||||
|
<div class="cat-list">
|
||||||
|
<?php foreach ($categories as $cat) :
|
||||||
|
$cid = (int) $cat['idservicecategory'];
|
||||||
|
$used = (int) ($catUsage[$cid] ?? 0); ?>
|
||||||
|
<span class="cat-chip">
|
||||||
|
<?php echo e($cat['namecategory']); ?>
|
||||||
|
<span class="cat-count"><?php echo $used; ?></span>
|
||||||
|
<button type="button" class="cat-rename" title="Rinomina" data-id="<?php echo $cid; ?>" data-name="<?php echo e($cat['namecategory']); ?>"><i class="fas fa-pen"></i></button>
|
||||||
|
<button type="button" class="cat-del" title="Elimina" data-id="<?php echo $cid; ?>" data-name="<?php echo e($cat['namecategory']); ?>" data-used="<?php echo $used; ?>"><i class="fas fa-xmark"></i></button>
|
||||||
|
</span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<p class="text-muted">Nessuna categoria: aggiungi la prima.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form method="post" class="row g-2" style="max-width:520px;">
|
||||||
|
<input type="hidden" name="cataction" value="add">
|
||||||
|
<div class="col-8">
|
||||||
|
<input type="text" name="namecategory" class="form-control" maxlength="50" placeholder="Nuova categoria" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<button type="submit" class="btn btn-primary w-100"><i class="fas fa-plus me-1"></i> Aggiungi</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form method="post" id="cat-action-form" class="d-none">
|
||||||
|
<input type="hidden" name="cataction" id="cat-action">
|
||||||
|
<input type="hidden" name="idservicecategory" id="cat-id">
|
||||||
|
<input type="hidden" name="namecategory" id="cat-name">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Elenco classi -->
|
<!-- Elenco classi -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@@ -513,6 +685,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
</tr>
|
</tr>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<?php foreach ($services as $svc) :
|
<?php foreach ($services as $svc) :
|
||||||
|
$sid = (int) $svc['idservice'];
|
||||||
$svcTeacherId = (int) $svc['idteacher'];
|
$svcTeacherId = (int) $svc['idteacher'];
|
||||||
$svcTeacher = $teachersById[$svcTeacherId] ?? null;
|
$svcTeacher = $teachersById[$svcTeacherId] ?? null;
|
||||||
?>
|
?>
|
||||||
@@ -521,7 +694,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<span class="color-dot" style="background-color: <?php echo e($svc['colorclass'] ?: '#ccc'); ?>;"></span>
|
<span class="color-dot" style="background-color: <?php echo e($svc['colorclass'] ?: '#ccc'); ?>;"></span>
|
||||||
<span class="font-size-14"><?php echo e($svc['servicename']); ?></span>
|
<span class="font-size-14"><?php echo e($svc['servicename']); ?></span>
|
||||||
</td>
|
</td>
|
||||||
<td><?php echo e($svc['day']); ?></td>
|
<td><?php echo e($dayLabels[$svc['day']] ?? $svc['day']); ?></td>
|
||||||
<td><?php echo e($svc['time']); ?></td>
|
<td><?php echo e($svc['time']); ?></td>
|
||||||
<td>
|
<td>
|
||||||
<i class="mdi mdi-clock-time-nine-outline align-middle font-size-16 me-1"></i>
|
<i class="mdi mdi-clock-time-nine-outline align-middle font-size-16 me-1"></i>
|
||||||
@@ -531,7 +704,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<td>
|
<td>
|
||||||
<form method="post" class="teacher-cell">
|
<form method="post" class="teacher-cell">
|
||||||
<input type="hidden" name="action" value="assignteacher">
|
<input type="hidden" name="action" value="assignteacher">
|
||||||
<input type="hidden" name="idservice" value="<?php echo (int) $svc['idservice']; ?>">
|
<input type="hidden" name="idservice" value="<?php echo $sid; ?>">
|
||||||
<?php if ($svcTeacher && $svcTeacher['photo']) : ?>
|
<?php if ($svcTeacher && $svcTeacher['photo']) : ?>
|
||||||
<img class="teacher-mini" src="assets/images/teachers/<?php echo e($svcTeacher['photo']); ?>" alt="">
|
<img class="teacher-mini" src="assets/images/teachers/<?php echo e($svcTeacher['photo']); ?>" alt="">
|
||||||
<?php elseif ($svcTeacher) :
|
<?php elseif ($svcTeacher) :
|
||||||
@@ -542,24 +715,21 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<select name="idteacher" class="form-select teacher-select <?php echo $svcTeacher ? '' : 'unassigned'; ?>"
|
<select name="idteacher" class="form-select teacher-select <?php echo $svcTeacher ? '' : 'unassigned'; ?>"
|
||||||
data-current="<?php echo $svcTeacherId; ?>"
|
data-current="<?php echo $svcTeacherId; ?>"
|
||||||
data-classname="<?php echo e($svc['servicename'] . ' ' . $svc['day'] . ' ' . $svc['time']); ?>">
|
data-classname="<?php echo e($svc['servicename'] . ' ' . ($dayLabels[$svc['day']] ?? $svc['day']) . ' ' . $svc['time']); ?>">
|
||||||
<?php echo teacherOptions($teachers, $svcTeacherId); ?>
|
<?php echo teacherOptions($teachers, $svcTeacherId); ?>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end action-btns">
|
<td class="text-end action-btns">
|
||||||
<button type="button" class="btn btn-primary btn-sm toggle-form">Propaga</button>
|
<button type="button" class="btn btn-primary btn-sm toggle-form">Propaga</button>
|
||||||
<a href="associate-services.php?id=<?php echo (int) $svc['idservice']; ?>">
|
<a href="associate-services.php?id=<?php echo $sid; ?>" class="btn btn-info btn-sm">Associa</a>
|
||||||
<button type="button" class="btn btn-info btn-sm">Associa</button>
|
<a href="updateservice.php?idservice=<?php echo $sid; ?>" class="btn btn-warning btn-sm" title="Modifica">
|
||||||
</a>
|
|
||||||
<a href="updateservice.php?idservice=<?php echo (int) $svc['idservice']; ?>" class="btn btn-warning btn-sm">
|
|
||||||
<i class="mdi mdi-lead-pencil font-size-16 align-middle"></i>
|
<i class="mdi mdi-lead-pencil font-size-16 align-middle"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="cancelservice.php?idservice=<?php echo (int) $svc['idservice']; ?>">
|
<button type="button" class="btn btn-danger btn-sm btn-delete-service" title="Elimina"
|
||||||
<button type="button" class="btn btn-danger btn-sm">
|
data-id="<?php echo $sid; ?>" data-name="<?php echo e($svc['servicename']); ?>">
|
||||||
<i class="bx bx-block font-size-16 align-middle"></i>
|
<i class="bx bx-block font-size-16 align-middle"></i>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="expanded-row">
|
<tr class="expanded-row">
|
||||||
@@ -570,20 +740,17 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Data inizio</label>
|
<label class="form-label">Data inizio</label>
|
||||||
<input type="text" class="datepicker form-control" name="propagatestartdate" required>
|
<input type="text" class="datepicker form-control" name="propagatestartdate" autocomplete="off" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">Data fine</label>
|
<label class="form-label">Data fine</label>
|
||||||
<input type="text" class="datepicker form-control" name="propagateenddate" required>
|
<input type="text" class="datepicker form-control" name="propagateenddate" autocomplete="off" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="idservice" value="<?php echo (int) $svc['idservice']; ?>">
|
<input type="hidden" name="idservice" value="<?php echo $sid; ?>">
|
||||||
<input type="hidden" name="timeclass" value="<?php echo e($svc['time']); ?>">
|
|
||||||
<input type="hidden" name="dayclass" value="<?php echo e($svc['day']); ?>">
|
|
||||||
<input type="hidden" name="durationtime" value="<?php echo e($svc['classduration']); ?>">
|
|
||||||
<button type="submit" class="btn btn-primary btn-save">Propaga sul calendario</button>
|
<button type="submit" class="btn btn-primary btn-save">Propaga sul calendario</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -607,7 +774,7 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
<td><?php echo e($p['startdate']); ?></td>
|
<td><?php echo e($p['startdate']); ?></td>
|
||||||
<td><?php echo e($p['enddate']); ?></td>
|
<td><?php echo e($p['enddate']); ?></td>
|
||||||
<td><?php echo e($p['occorrenze']); ?></td>
|
<td><?php echo e($p['occorrenze']); ?></td>
|
||||||
<td><code style="font-size:11px;"><?php echo e(substr((string)$p['token'], 0, 10)); ?>…</code></td>
|
<td><code style="font-size:11px;"><?php echo e(substr((string) $p['token'], 0, 10)); ?>…</code></td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<a href="cancelpropagation.php?token=<?php echo e($p['token']); ?>"
|
<a href="cancelpropagation.php?token=<?php echo e($p['token']); ?>"
|
||||||
class="btn btn-danger btn-sm"
|
class="btn btn-danger btn-sm"
|
||||||
@@ -647,12 +814,10 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Datepicker sui campi di propagazione
|
|
||||||
$(".datepicker").datepicker({
|
$(".datepicker").datepicker({
|
||||||
dateFormat: "yy-mm-dd"
|
dateFormat: "yy-mm-dd"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Color picker spectrum collegato al VERO campo colorclass (ora viene salvato)
|
|
||||||
$('#colorclass').spectrum({
|
$('#colorclass').spectrum({
|
||||||
preferredFormat: 'hex',
|
preferredFormat: 'hex',
|
||||||
showInput: true,
|
showInput: true,
|
||||||
@@ -663,37 +828,84 @@ function teacherOptions(array $teachers, int $selectedId): string
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// Forza il valore del colore nel campo prima dell'invio del form
|
|
||||||
$('#insertclass').on('submit', function() {
|
$('#insertclass').on('submit', function() {
|
||||||
var col = $('#colorclass').spectrum('get');
|
var col = $('#colorclass').spectrum('get');
|
||||||
if (col) {
|
if (col) $('#colorclass').val(col.toHexString());
|
||||||
$('#colorclass').val(col.toHexString());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cambio insegnante dalla tabella: conferma e salva
|
// Cambio insegnante dalla tabella: conferma e salva
|
||||||
$('.teacher-select').on('change', function() {
|
$('.teacher-select').on('change', function() {
|
||||||
var sel = $(this);
|
var sel = $(this);
|
||||||
var teacherName = sel.find('option:selected').text();
|
if (confirm('Assegnare ' + sel.find('option:selected').text() + ' alla classe ' + sel.data('classname') + '?')) {
|
||||||
if (confirm('Assegnare ' + teacherName + ' alla classe ' + sel.data('classname') + '?')) {
|
|
||||||
sel.closest('form')[0].submit();
|
sel.closest('form')[0].submit();
|
||||||
} else {
|
} else {
|
||||||
sel.val(String(sel.data('current')) === '0' ? '' : String(sel.data('current')));
|
sel.val(String(sel.data('current')) === '0' ? '' : String(sel.data('current')));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Espansione riga propagazione
|
// Eliminazione classe con conferma
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
$('.btn-delete-service').on('click', function() {
|
||||||
document.querySelectorAll(".toggle-form").forEach(function(button) {
|
var id = $(this).data('id');
|
||||||
button.addEventListener("click", function() {
|
Swal.fire({
|
||||||
var row = this.closest("tr");
|
title: 'Eliminare questa classe?',
|
||||||
var expandedRow = row.nextElementSibling;
|
html: '<strong>' + $('<div>').text($(this).data('name')).html() + '</strong><br><br>Possibile solo se non ha lezioni o ordini collegati.',
|
||||||
if (expandedRow && expandedRow.classList.contains("expanded-row")) {
|
icon: 'warning',
|
||||||
expandedRow.classList.toggle("expanded");
|
showCancelButton: true,
|
||||||
}
|
confirmButtonColor: '#e74c3c',
|
||||||
|
confirmButtonText: 'Sì, elimina',
|
||||||
|
cancelButtonText: 'Annulla'
|
||||||
|
}).then(function(r) {
|
||||||
|
if (r.isConfirmed) window.location.href = 'cancelservice.php?idservice=' + id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Categorie: rinomina / elimina
|
||||||
|
function catSubmit(action, id, name) {
|
||||||
|
$('#cat-action').val(action);
|
||||||
|
$('#cat-id').val(id);
|
||||||
|
$('#cat-name').val(name || '');
|
||||||
|
$('#cat-action-form')[0].submit();
|
||||||
|
}
|
||||||
|
$('.cat-rename').on('click', function() {
|
||||||
|
const id = $(this).data('id');
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Rinomina categoria',
|
||||||
|
input: 'text',
|
||||||
|
inputValue: $(this).data('name'),
|
||||||
|
inputAttributes: {
|
||||||
|
maxlength: 50
|
||||||
|
},
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Salva',
|
||||||
|
cancelButtonText: 'Annulla',
|
||||||
|
inputValidator: v => !v.trim() ? 'Inserisci un nome' : null
|
||||||
|
}).then(r => {
|
||||||
|
if (r.isConfirmed) catSubmit('rename', id, r.value.trim());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$('.cat-del').on('click', function() {
|
||||||
|
const id = $(this).data('id');
|
||||||
|
if (parseInt($(this).data('used'), 10) > 0) {
|
||||||
|
Swal.fire('Categoria in uso', 'Cambia prima la categoria delle classi che la usano.', 'info');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Eliminare la categoria?',
|
||||||
|
html: '<strong>' + $('<div>').text($(this).data('name')).html() + '</strong>',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#e74c3c',
|
||||||
|
confirmButtonText: 'Sì, elimina',
|
||||||
|
cancelButtonText: 'Annulla'
|
||||||
|
}).then(r => {
|
||||||
|
if (r.isConfirmed) catSubmit('delete', id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Espansione riga propagazione
|
||||||
|
$('.toggle-form').on('click', function() {
|
||||||
|
$(this).closest('tr').next('.expanded-row').toggleClass('expanded');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,285 +0,0 @@
|
|||||||
<?php require_once('Connections/bkngstm.php'); ?>
|
|
||||||
<?php require_once('webassist/mysqli/rsobj.php'); ?>
|
|
||||||
<?php
|
|
||||||
$servicesclass = new WA_MySQLi_RS("servicesclass",$bkngstm,0);
|
|
||||||
$servicesclass->setQuery("SELECT * FROM service LEFT JOIN servicecategory on service.category=servicecategory.idservicecategory");
|
|
||||||
$servicesclass->execute();
|
|
||||||
?>
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>YogiBook - Prenotazioni YogaSoul</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta content="YogiBook - Prenotazione facile YogaSOul" name="description" />
|
|
||||||
<meta content="Advanced Creative Solutions" name="author" />
|
|
||||||
<!-- App favicon -->
|
|
||||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
|
||||||
|
|
||||||
<!-- Bootstrap Css -->
|
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
|
||||||
<!-- Icons Css -->
|
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
|
||||||
<!-- App Css-->
|
|
||||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- <body data-layout="horizontal"> -->
|
|
||||||
|
|
||||||
<!-- Begin page -->
|
|
||||||
<div id="layout-wrapper">
|
|
||||||
|
|
||||||
<!-- Top Bar -->
|
|
||||||
<header id="page-topbar" class="isvertical-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex">
|
|
||||||
<!-- LOGO -->
|
|
||||||
<?php include('include/logoarea.php'); ?>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-sm px-3 font-size-24 header-item waves-effect vertical-menu-btn">
|
|
||||||
<i class="bx bx-menu align-middle"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- start page title -->
|
|
||||||
<div class="page-title-box align-self-center d-none d-md-block">
|
|
||||||
<h4 class="page-title mb-0">Inserimento e Propagazione Classi</h4>
|
|
||||||
</div>
|
|
||||||
<!-- end page title -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex">
|
|
||||||
|
|
||||||
<?php include('include/languageselection.php'); ?>
|
|
||||||
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button type="button" class="btn header-item noti-icon"
|
|
||||||
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<i class="bx bx-search icon-sm align-middle"></i>
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-end p-0">
|
|
||||||
<form class="p-2">
|
|
||||||
<div class="search-box">
|
|
||||||
<div class="position-relative">
|
|
||||||
<input type="text" class="form-control rounded bg-light border-0" placeholder="Search...">
|
|
||||||
<i class="bx bx-search search-icon"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<?php include('include/sidebar.php'); ?>
|
|
||||||
|
|
||||||
<header class="ishorizontal-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="topnav">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<nav class="navbar navbar-light navbar-expand-lg topnav-menu">
|
|
||||||
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- ============================================================== -->
|
|
||||||
<!-- Start right Content here -->
|
|
||||||
<!-- ============================================================== -->
|
|
||||||
<div class="main-content">
|
|
||||||
<div class="page-content">
|
|
||||||
<div class="container-fluid">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5>Benvenuta/o </h5>
|
|
||||||
<p>Di seguito puoi vedere lo stato delle tue prenotazioni</p>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table mb-0">
|
|
||||||
<thead class="table-light">
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th>Lezioni acquistate</th>
|
|
||||||
<th>Da prenotare</th>
|
|
||||||
<th>Prenotate</th>
|
|
||||||
<th>Effettuate</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
|
|
||||||
<td>Table cell</td>
|
|
||||||
<td>Table cell</td>
|
|
||||||
<td>Table cell</td>
|
|
||||||
<td>Table cell</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- container-fluid -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<div class="row mb-2">
|
|
||||||
<div class="col-xl-3 col-md-12">
|
|
||||||
<div class="pb-3 pb-xl-0">
|
|
||||||
<form class="email-search">
|
|
||||||
<div class="position-relative">
|
|
||||||
<input type="text" class="form-control bg-light" placeholder="Search...">
|
|
||||||
<span class="bx bx-search font-size-18"></span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xl-9 col-md-12">
|
|
||||||
<div class="text-sm-end">
|
|
||||||
<button type="button" class="btn btn-success btn-rounded waves-effect waves-light mb-2 me-2" data-bs-toggle="modal" data-bs-target=".create-task"><i class="mdi mdi-plus me-1"></i> Acquista Pacchetto Lezioni</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-nowrap align-middle mb-0">
|
|
||||||
<thead class="table-light">
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th> </th>
|
|
||||||
<th> Classe </th>
|
|
||||||
<th> Durata </th>
|
|
||||||
<th> Appuntamento </th>
|
|
||||||
<th> Status </th>
|
|
||||||
<th> Action </th>
|
|
||||||
</tr> </thead>
|
|
||||||
<tbody>
|
|
||||||
<?php
|
|
||||||
$wa_startindex = 0;
|
|
||||||
while(!$servicesclass->atEnd()) {
|
|
||||||
$wa_startindex = $servicesclass->Index;
|
|
||||||
?>
|
|
||||||
<tr>
|
|
||||||
<td style="width: 40px;">
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<h5 class="text-truncate font-size-14 m-0"><a href="javascript: void(0);" class="text-dark"><?php echo($servicesclass->getColumnVal("servicename")); ?></a></h5>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<p class="mb-0">
|
|
||||||
<i class="mdi mdi-clock-time-nine-outline align-middle font-size-16 me-1"></i> <?php echo($servicesclass->getColumnVal("day")); ?>
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<p class="mb-0"><?php echo($servicesclass->getColumnVal("time")); ?></p>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<div class="text-center">
|
|
||||||
<span class="badge rounded-pill badge-soft-success font-size-11">Prenotato</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button type="button" class="btn btn-warning waves-effect waves-light">
|
|
||||||
<i class="bx bx-error font-size-16 align-middle me-2"></i> Riprogramma
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-danger waves-effect waves-light">
|
|
||||||
<i class="bx bx-block font-size-16 align-middle me-2"></i> Cancella
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
$servicesclass->moveNext();
|
|
||||||
}
|
|
||||||
$servicesclass->moveFirst(); //return RS to first record
|
|
||||||
unset($wa_startindex);
|
|
||||||
unset($wa_repeatcount);
|
|
||||||
?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- container-fluid -->
|
|
||||||
</div>
|
|
||||||
<!-- End Page-content -->
|
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
|
||||||
</div>
|
|
||||||
<!-- end main content-->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- END layout-wrapper -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- JAVASCRIPT -->
|
|
||||||
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
|
||||||
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
|
||||||
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
|
||||||
|
|
||||||
<script src="assets/js/app.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,884 +0,0 @@
|
|||||||
<?php require_once('include/headscript.php'); ?>
|
|
||||||
<?php // require_once('Connections/bkngstm.php'); ?>
|
|
||||||
<?php // require_once('webassist/mysqli/rsobj.php'); ?>
|
|
||||||
<?php // require_once('webassist/mysqli/queryobj.php'); ?>
|
|
||||||
<?php // optionquery
|
|
||||||
$optionquery = new WA_MySQLi_RS("optionquery",$bkngstm,0);
|
|
||||||
$optionquery->setQuery("SELECT * FROM option");
|
|
||||||
$optionquery->execute();
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
$bookedclass = new WA_MySQLi_RS("bookedclass", $bkngstm, 0);
|
|
||||||
|
|
||||||
// Verifica se è stata specificata una richiesta per cambiare il mese
|
|
||||||
if (isset($_GET['prev_month'])) {
|
|
||||||
$currentMonthStart = $_GET['prev_month'] . '-01';
|
|
||||||
} elseif (isset($_GET['next_month'])) {
|
|
||||||
$currentMonthStart = $_GET['next_month'] . '-01';
|
|
||||||
} else {
|
|
||||||
$currentMonthStart = date("Y-m-01");
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentDate = date("Y-m-d");
|
|
||||||
|
|
||||||
// Modifica: Se la data odierna è dopo l'inizio del mese corrente, imposta la data odierna come inizio
|
|
||||||
//if ($currentDate > $currentMonthStart) {
|
|
||||||
// $currentMonthStart = $currentDate;
|
|
||||||
//}
|
|
||||||
|
|
||||||
$currentMonthEnd = date("Y-m-t", strtotime($currentMonthStart));
|
|
||||||
|
|
||||||
$bookedclass->setQuery("SELECT * FROM serviceschedule
|
|
||||||
LEFT JOIN service ON serviceschedule.idservice = service.idservice
|
|
||||||
WHERE serviceschedule.dateschedule BETWEEN '$currentMonthStart' AND DATE_ADD('$currentMonthEnd', INTERVAL 1 DAY) ORDER BY serviceschedule.dateschedule");
|
|
||||||
$bookedclass->execute();
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID dell'utente per il quale vuoi filtrare gli ordini
|
|
||||||
$userid = 1;
|
|
||||||
|
|
||||||
// Query per ottenere la somma dei ticket per ogni ordine dell'utente
|
|
||||||
$query = "SELECT iduser, idorderbook, SUM(nticket) as total_tickets
|
|
||||||
FROM orderbook
|
|
||||||
WHERE iduser = $userid
|
|
||||||
GROUP BY iduser";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
die("Query fallita: " . $conn->error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$idOrdine = $row["idorderbook"];
|
|
||||||
$totalTickets = $row["total_tickets"];
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$totalTickets = 0; // Imposta a zero se non ci sono righe nella query
|
|
||||||
}
|
|
||||||
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
<?php //check tickets
|
|
||||||
// Connessione al database
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID dell'utente per il quale si desidera eseguire la query
|
|
||||||
$iduser = 1; // Sostituisci con l'ID utente desiderato
|
|
||||||
|
|
||||||
// Data e ora attuali
|
|
||||||
$currentDateTime = date("Y-m-d H:i:s");
|
|
||||||
|
|
||||||
// Query per contare i record con data e ora passate e future
|
|
||||||
$query = "SELECT COUNT(*) AS total,
|
|
||||||
SUM(CASE WHEN serviceschedule.dateschedule <= '$currentDateTime' THEN 1 ELSE 0 END) AS passed,
|
|
||||||
SUM(CASE WHEN serviceschedule.dateschedule > '$currentDateTime' THEN 1 ELSE 0 END) AS future
|
|
||||||
FROM bookingclass
|
|
||||||
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
|
|
||||||
WHERE bookingclass.iduser = $iduser";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
if ($result) {
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
$totalRecords = $row['total'];
|
|
||||||
$passedRecords = $row['passed'];
|
|
||||||
$futureRecords = $row['future'];
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
// Chiusura della connessione
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>YogiBook - Prenotazioni YogaSoul</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta content="YogiBook - Prenotazione facile YogaSOul" name="description" />
|
|
||||||
<meta content="Advanced Creative Solutions" name="author" />
|
|
||||||
<!-- App favicon -->
|
|
||||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
|
||||||
|
|
||||||
<!-- Bootstrap Css -->
|
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
|
||||||
<!-- Icons Css -->
|
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
|
||||||
<!-- App Css-->
|
|
||||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
|
||||||
<script>
|
|
||||||
// Function to handle the click event on the "Rimuovi" button
|
|
||||||
function handleRemoveClick(idbookingclass) {
|
|
||||||
// Display SweetAlert confirmation
|
|
||||||
Swal.fire({
|
|
||||||
title: 'Sei sicuro?',
|
|
||||||
text: 'Questa azione rimuoverà la persona dalla classe. Vuoi procedere?',
|
|
||||||
icon: 'warning',
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonText: 'Sì, rimuovi!',
|
|
||||||
cancelButtonText: 'Annulla',
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
// If user confirms, redirect to the removebooking.php page
|
|
||||||
window.location.href = `removebooking.php?idbookingclass=${idbookingclass}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
$(".lost-button").click(function() {
|
|
||||||
var idbookingclass = $(this).data("idbookingclass");
|
|
||||||
|
|
||||||
// Mostra un SweetAlert di conferma
|
|
||||||
Swal.fire({
|
|
||||||
title: 'Sei sicuro?',
|
|
||||||
text: 'Vuoi davvero contrassegnare questa lezione come persa?',
|
|
||||||
icon: 'warning',
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonText: 'Sì, contrassegna come persa',
|
|
||||||
cancelButtonText: 'Annulla'
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
// Se l'utente conferma, esegui l'aggiornamento
|
|
||||||
$.ajax({
|
|
||||||
url: "aggiorna_campo_lost.php",
|
|
||||||
method: "POST",
|
|
||||||
data: { idbookingclass: idbookingclass },
|
|
||||||
success: function(response) {
|
|
||||||
// Dopo aver contrassegnato con successo la lezione come persa, reindirizza all'adminpanel
|
|
||||||
window.location.href = 'adminpanel.php?success=1';
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
Swal.fire('Errore durante l\'aggiornamento', '', 'error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.lost-button {
|
|
||||||
background-color: orange; /* Imposta il colore arancione */
|
|
||||||
color: white; /* Imposta il testo in bianco o altro colore a tua scelta */
|
|
||||||
border: none;
|
|
||||||
padding: 6px 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lost-button:hover {
|
|
||||||
background-color: darkorange; /* Cambia il colore al passaggio del mouse se lo desideri */
|
|
||||||
}
|
|
||||||
|
|
||||||
.email-search-results {
|
|
||||||
position: absolute; /* O posizionamento relativo a seconda delle esigenze */
|
|
||||||
top: 100%; /* Posizionamento rispetto all'elemento padre */
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: white; /* Colore di sfondo */
|
|
||||||
border: 1px solid #ccc; /* Bordo */
|
|
||||||
max-height: 200px; /* Altezza massima */
|
|
||||||
overflow-y: auto; /* Scorrimento verticale se i risultati superano l'altezza massima */
|
|
||||||
z-index: 1000; /* Per sovrapporre altri elementi */
|
|
||||||
display: none; /* Inizialmente nascosto */
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card {
|
|
||||||
margin: 10px auto;
|
|
||||||
display: flex;
|
|
||||||
width: 90%;
|
|
||||||
max-width: 700px;
|
|
||||||
background-color: white;
|
|
||||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card:hover {
|
|
||||||
transform: translateY(-5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-date-box {
|
|
||||||
flex: 1;
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 60px;
|
|
||||||
font-weight: bold;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-bottom-left-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-day {
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-month {
|
|
||||||
font-size: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-event-details {
|
|
||||||
flex: 2;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 10px 20px;
|
|
||||||
background-color: #AEEAF5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-heading {
|
|
||||||
margin-top: 0;
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-paragraph {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-actions {
|
|
||||||
display: none;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card.expanded .custom-actions {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-action-button {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
border: none;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-action-button:hover {
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.custom-card {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-date-box, .custom-event-details {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-event-time {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style>
|
|
||||||
.month-navigation {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.month-nav-button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-month {
|
|
||||||
font-size: 24px;
|
|
||||||
margin: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
function confirmDelete(id, deletePageUrl) {
|
|
||||||
Swal.fire({
|
|
||||||
title: "Sei sicuro?",
|
|
||||||
text: "Questa prenotazione verrà cancellata definitivamente! Ricordati poi di riprogrammare la tua lezione!",
|
|
||||||
icon: "warning",
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonColor: "#d33",
|
|
||||||
cancelButtonColor: "#3085d6",
|
|
||||||
confirmButtonText: "Sì, cancella!",
|
|
||||||
cancelButtonText: "Annulla"
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
// Reindirizza direttamente alla pagina di cancellazione con l'ID come parametro.
|
|
||||||
window.location.href = `deleteclass.php?id=${id}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.pastel-color {
|
|
||||||
border: 1px solid #D1C4CC;
|
|
||||||
padding: 0px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 20px; /* Spazio tra i box */
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.blue {
|
|
||||||
background-color: #D4E1F1; /* Azzurro pastello */
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.green {
|
|
||||||
background-color: #FFD8B5; /* Verde pastello */
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.pink {
|
|
||||||
background-color: #C3E6CB; /* Rosa pastello */
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.purple {
|
|
||||||
background-color: #F4CCCC; /* Viola pastello */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.pastel-color {
|
|
||||||
margin-right: 0; /* Rimuovi lo spazio tra i box */
|
|
||||||
margin-bottom: 20px; /* Spazio tra i box */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style>
|
|
||||||
.booking-details {
|
|
||||||
margin-top: 10px;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 5px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
border: 1px solid #333; /* Aggiunto il bordo grigio scuro */
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-row td {
|
|
||||||
padding: 2px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-cell {
|
|
||||||
text-align: left; /* Allinea il contenuto a sinistra */
|
|
||||||
vertical-align: top; /* Allinea il contenuto in alto */
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
display: block; /* Per occupare l'intera larghezza del cell */
|
|
||||||
padding: 6px 12px;
|
|
||||||
border: none;
|
|
||||||
background-color: #e74c3c;
|
|
||||||
color: white;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button:hover {
|
|
||||||
background-color: #d64937;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- <body data-layout="horizontal"> -->
|
|
||||||
|
|
||||||
<!-- Begin page -->
|
|
||||||
<div id="layout-wrapper">
|
|
||||||
|
|
||||||
<!-- Top Bar -->
|
|
||||||
<header id="page-topbar" class="isvertical-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex">
|
|
||||||
<!-- LOGO -->
|
|
||||||
<?php include('include/logoarea.php'); ?>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-sm px-3 font-size-24 header-item waves-effect vertical-menu-btn">
|
|
||||||
<i class="bx bx-menu align-middle"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- start page title -->
|
|
||||||
<div class="page-title-box align-self-center d-none d-md-block">
|
|
||||||
<h4 class="page-title mb-0">Prenotazione Classi</h4>
|
|
||||||
</div>
|
|
||||||
<!-- end page title -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex">
|
|
||||||
|
|
||||||
<?php include('include/languageselection.php'); ?>
|
|
||||||
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button type="button" class="btn header-item noti-icon"
|
|
||||||
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<i class="bx bx-search icon-sm align-middle"></i>
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-end p-0">
|
|
||||||
<form class="p-2">
|
|
||||||
<div class="search-box">
|
|
||||||
<div class="position-relative">
|
|
||||||
<input type="text" class="form-control rounded bg-light border-0" placeholder="Search...">
|
|
||||||
<i class="bx bx-search search-icon"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<?php include('include/sidebar.php'); ?>
|
|
||||||
|
|
||||||
<header class="ishorizontal-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="topnav">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<nav class="navbar navbar-light navbar-expand-lg topnav-menu">
|
|
||||||
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- ============================================================== -->
|
|
||||||
<!-- Start right Content here -->
|
|
||||||
<!-- ============================================================== -->
|
|
||||||
<div class="main-content">
|
|
||||||
<div class="page-content">
|
|
||||||
<div class="container-fluid">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$toprogram = $totalTickets - $passedRecords - $futureRecords;
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- container-fluid -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<div class="row mb-2">
|
|
||||||
<div class="col-xl-3 col-md-12">
|
|
||||||
<div class="pb-3 pb-xl-0">
|
|
||||||
<form class="email-search">
|
|
||||||
<div class="position-relative">
|
|
||||||
<h3>Classi</h3>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xl-9 col-md-12">
|
|
||||||
<div class="text-sm-end">
|
|
||||||
<?php if ($toprogram > 0) {
|
|
||||||
echo '<button type="button" class="btn btn-info btn-rounded waves-effect waves-light mb-2 me-2" data-bs-toggle="modal" data-bs-target=".create-task"><i class="mdi mdi-plus me-1"></i> Programma Lezioni</button>';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- container-fluid -->
|
|
||||||
<?php
|
|
||||||
if(isset($_GET['success']) && $_GET['success'] == 1) { ?>
|
|
||||||
|
|
||||||
<div class="alert alert-danger success-message" role="alert">
|
|
||||||
Lezione segnata come persa con successo
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<!-- starts cards -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Aggiungi le frecce per la navigazione tra i mesi -->
|
|
||||||
<?php
|
|
||||||
$italianMonths = [
|
|
||||||
"January" => "Gennaio",
|
|
||||||
"February" => "Febbraio",
|
|
||||||
"March" => "Marzo",
|
|
||||||
"April" => "Aprile",
|
|
||||||
"May" => "Maggio",
|
|
||||||
"June" => "Giugno",
|
|
||||||
"July" => "Luglio",
|
|
||||||
"August" => "Agosto",
|
|
||||||
"September" => "Settembre",
|
|
||||||
"October" => "Ottobre",
|
|
||||||
"November" => "Novembre",
|
|
||||||
"December" => "Dicembre"
|
|
||||||
];
|
|
||||||
|
|
||||||
?>
|
|
||||||
<div class="month-navigation">
|
|
||||||
<a href="?prev_month=<?php echo date('Y-m', strtotime('-1 month', strtotime($currentMonthStart))); ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-left fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
<h2><?php echo $italianMonths[date("F", strtotime($currentMonthStart))] . ' ' . date("Y", strtotime($currentMonthStart)); ?></h2>
|
|
||||||
<a href="?next_month=<?php echo date('Y-m', strtotime('+1 month', strtotime($currentMonthStart))); ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-right fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$wa_startindex = 0;
|
|
||||||
|
|
||||||
if ($bookedclass->TotalRows == 0) {
|
|
||||||
echo "<p>Classi non presenti per questo mese</p>";
|
|
||||||
} else {
|
|
||||||
while (!$bookedclass->atEnd()) {
|
|
||||||
$wa_startindex = $bookedclass->Index;
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
// Data dalla variabile $bookedclass->getColumnVal("dateschedule")
|
|
||||||
$dateschedule = $bookedclass->getColumnVal("dateschedule");
|
|
||||||
|
|
||||||
// Converti la data in un oggetto DateTime
|
|
||||||
$dateObj = new DateTime($dateschedule);
|
|
||||||
|
|
||||||
// Estrai il giorno e il mese in italiano
|
|
||||||
$dayInItalian = $dateObj->format("d");
|
|
||||||
$monthInItalian = $dateObj->format("F");
|
|
||||||
|
|
||||||
// Mappa dei nomi dei mesi in italiano
|
|
||||||
$italianMonths = [
|
|
||||||
"January" => "Gennaio",
|
|
||||||
"February" => "Febbraio",
|
|
||||||
"March" => "Marzo",
|
|
||||||
"April" => "Aprile",
|
|
||||||
"May" => "Maggio",
|
|
||||||
"June" => "Giugno",
|
|
||||||
"July" => "Luglio",
|
|
||||||
"August" => "Agosto",
|
|
||||||
"September" => "Settembre",
|
|
||||||
"October" => "Ottobre",
|
|
||||||
"November" => "Novembre",
|
|
||||||
"December" => "Dicembre"
|
|
||||||
];
|
|
||||||
|
|
||||||
// Sostituisci il nome del mese con la versione italiana
|
|
||||||
$monthInItalian = $italianMonths[$monthInItalian];
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
// Data dalla variabile $bookedclass->getColumnVal("dateschedule")
|
|
||||||
$dateschedule = $bookedclass->getColumnVal("dateschedule");
|
|
||||||
|
|
||||||
// Converti la data in un oggetto DateTime
|
|
||||||
$dateObj = new DateTime($dateschedule);
|
|
||||||
|
|
||||||
// Formatta la data nel nuovo formato desiderato
|
|
||||||
$newDateFormat = $dateObj->format("d-m-Y H:i");
|
|
||||||
|
|
||||||
// Calculate the time difference in hours
|
|
||||||
$currentTime = new DateTime();
|
|
||||||
$classTime = new DateTime($dateschedule);
|
|
||||||
$timeDifference = $classTime->diff($currentTime);
|
|
||||||
$hoursDifference = $timeDifference->h + $timeDifference->days * 24;
|
|
||||||
|
|
||||||
// Check if the time difference is less than 6 hours
|
|
||||||
$timetocancel=$optionquery->getColumnVal("maxbeforetimecancell");
|
|
||||||
$canBeDeleted = ($hoursDifference >= $timetocancel);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
|
||||||
<?php $mysqli = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
// Esegui una nuova query per ottenere le persone prenotate per l'evento corrente
|
|
||||||
$eventId = $bookedclass->getColumnVal("idserviceschedule");
|
|
||||||
$bookingQuery = "SELECT * FROM bookingclass LEFT JOIN auth_users ON bookingclass.iduser=auth_users.id
|
|
||||||
WHERE bookingclass.idserviceschedule = $eventId AND bookingclass.status='booked'";
|
|
||||||
$bookingResult = $mysqli->query($bookingQuery);
|
|
||||||
|
|
||||||
// Calcola il numero di persone prenotate
|
|
||||||
$countPersons = $bookingResult->num_rows;
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="custom-card" onclick="toggleCard(this)">
|
|
||||||
<div class="custom-date-box" style="background-color:#3BDD79">
|
|
||||||
<div class="custom-day"><?php echo $dayInItalian; ?></div>
|
|
||||||
<div class="custom-month"><?php echo $monthInItalian; ?></div>
|
|
||||||
</div>
|
|
||||||
<div class="custom-event-details" style="background-color:<?php echo($bookedclass->getColumnVal("colorclass")); ?>">
|
|
||||||
<h2 class="custom-heading"><?php echo($bookedclass->getColumnVal("servicename")); ?> -<?php echo $countPersons; ?>/<?php echo($bookedclass->getColumnVal("maxcapacity")); ?></h2>
|
|
||||||
<p class="custom-paragraph">Quando: <?php echo $newDateFormat; ?></p>
|
|
||||||
<p class="custom-paragraph">Luogo: via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
|
||||||
<div class="custom">
|
|
||||||
<button class="custom-action-button" onclick="toggleCustomContent(this, 'bookings')"><i class="fas fa-list-plus"></i> Vedi prenotazioni</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="custom-actions">
|
|
||||||
<table class="booking-table">
|
|
||||||
<?php while ($booking = $bookingResult->fetch_assoc()) : ?>
|
|
||||||
<tr class="booking-row">
|
|
||||||
<?php $idbookedclass = $booking['idbookingclass']; ?>
|
|
||||||
<td><?php echo $booking['first_name']; ?> <?php echo $booking['last_name']; ?></td>
|
|
||||||
<td class="delete-cell">
|
|
||||||
<button class="delete-button" onclick="handleRemoveClick(<?php echo $idbookedclass; ?>)">
|
|
||||||
<i class="fa fa-trash"></i> Rimuovi
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<td class="lost-cell">
|
|
||||||
<button class="lost-button" data-idbookingclass="<?php echo $idbookedclass; ?>">
|
|
||||||
<i class="fas fa-wind"></i> Persa
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
<?php endwhile; ?>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<form action="inserisci_record.php" method="post">
|
|
||||||
<label for="name">Nome:</label>
|
|
||||||
<input type="text" class="name" name="name"><br><br>
|
|
||||||
|
|
||||||
<label for="surname">Cognome:</label>
|
|
||||||
<input type="text" class="surname" name="surname"><br><br>
|
|
||||||
|
|
||||||
|
|
||||||
<label for="email">Email:</label>
|
|
||||||
<input type="text" class="email" name="email"><br><br>
|
|
||||||
<input type="hidden" class="userid" name="userid">
|
|
||||||
<input type="hidden" id="idserviceschedule" name="idserviceschedule" value="<?php echo $bookedclass->getColumnVal("idserviceschedule"); ?>">
|
|
||||||
<input type="hidden" id="status" name="status" value="booked">
|
|
||||||
<input type="hidden" id="idorder" name="idorder" value="0">
|
|
||||||
<input type="hidden" id="idservice" name="idservice" value="<?php echo $bookedclass->getColumnVal("idservice"); ?>">
|
|
||||||
<input type="hidden" id="bookingstart" name="bookingstart" value="<?php echo $dateschedule; ?>">
|
|
||||||
|
|
||||||
|
|
||||||
<button type="submit">Inserisci</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="search-results"></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
$(".surname").on("input", function() {
|
|
||||||
var searchTerm = $(this).val();
|
|
||||||
var currentForm = $(this).closest('form'); // Riferimento alla form corrente
|
|
||||||
|
|
||||||
if (searchTerm.length >= 2) {
|
|
||||||
$.ajax({
|
|
||||||
url: "searchemail.php",
|
|
||||||
method: "POST",
|
|
||||||
data: { searchTerm: searchTerm },
|
|
||||||
dataType: "json",
|
|
||||||
success: function(data) {
|
|
||||||
var results = data.results;
|
|
||||||
currentForm.next('.search-results').empty();
|
|
||||||
|
|
||||||
if (results.length > 0) {
|
|
||||||
currentForm.next('.search-results').append("<p>Seleziona un utente:</p>");
|
|
||||||
|
|
||||||
for (var i = 0; i < results.length; i++) {
|
|
||||||
var user = results[i];
|
|
||||||
currentForm.next('.search-results').append(
|
|
||||||
'<div class="user-result" data-email="' + user.email + '" data-userid="' + user.id + '" data-firstname="' + user.first_name + '" data-lastname="' + user.last_name + '">' +
|
|
||||||
'Email: ' + user.email + ' | Nome: ' + user.first_name + ' | Cognome: ' + user.last_name +
|
|
||||||
'</div>'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(".user-result").click(function() {
|
|
||||||
var selectedEmail = $(this).data("email");
|
|
||||||
var selectedUserId = $(this).data("userid");
|
|
||||||
var selectedFirstName = $(this).data("firstname");
|
|
||||||
var selectedLastName = $(this).data("lastname");
|
|
||||||
|
|
||||||
currentForm.find(".email").val(selectedEmail);
|
|
||||||
currentForm.find(".userid").val(selectedUserId); // Cambiato ".serid" in ".userid" poiché sembra un errore nel tuo codice
|
|
||||||
currentForm.find(".name").val(selectedFirstName);
|
|
||||||
currentForm.find(".surname").val(selectedLastName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
currentForm.next('.search-results').empty();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleCard(card) {
|
|
||||||
card.classList.toggle("expanded");
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleCustomContent(button, content) {
|
|
||||||
const card = button.closest('.custom-card');
|
|
||||||
const bookings = card.querySelector('.custom-actions');
|
|
||||||
const addForm = card.querySelector('.add-booking-form');
|
|
||||||
|
|
||||||
if (content === 'bookings') {
|
|
||||||
bookings.style.display = 'block';
|
|
||||||
addForm.style.display = 'none';
|
|
||||||
} else if (content === 'addForm') {
|
|
||||||
addForm.style.display = 'block';
|
|
||||||
bookings.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$bookedclass->moveNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bookedclass->moveFirst(); // Ritorna all'inizio del recordset
|
|
||||||
unset($wa_startindex);
|
|
||||||
unset($wa_repeatcount);
|
|
||||||
?>
|
|
||||||
<!-- Aggiungi altre card qui con le stesse classi -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleCard(card) {
|
|
||||||
card.classList.toggle("expanded");
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- End Page-content -->
|
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
|
||||||
</div>
|
|
||||||
<!-- end main content-->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- END layout-wrapper -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- JAVASCRIPT -->
|
|
||||||
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
|
||||||
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
|
||||||
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
|
||||||
|
|
||||||
<script src="assets/js/app.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -7,6 +7,7 @@ require_once('include/headscript.php');
|
|||||||
* manuale e cancellazione completa di una classe schedulata.
|
* manuale e cancellazione completa di una classe schedulata.
|
||||||
*/
|
*/
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
SchoolContext::requireStaff();
|
||||||
|
|
||||||
function e($value): string
|
function e($value): string
|
||||||
{
|
{
|
||||||
@@ -28,17 +29,24 @@ function avatarColor(string $seed): string
|
|||||||
return $palette[$idx];
|
return $palette[$idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
$optRow = $pdo->query("SELECT maxbeforetimecancell, show_teacher FROM `option` LIMIT 1")->fetch();
|
$timetocancel = (int) SchoolSettings::get('maxbeforetimecancell', 24);
|
||||||
$timetocancel = $optRow ? (int) $optRow['maxbeforetimecancell'] : 24;
|
$showTeacher = SchoolSettings::get('show_teacher', 'N') === 'Y';
|
||||||
$showTeacher = ($optRow['show_teacher'] ?? 'N') === 'Y';
|
|
||||||
|
|
||||||
$teachersById = [];
|
$teachersById = [];
|
||||||
if ($showTeacher) {
|
if ($showTeacher) {
|
||||||
foreach ($pdo->query("SELECT idemployee, nameemployee, surnameemployee, photo FROM employee")->fetchAll() as $t) {
|
$stT = $pdo->prepare("SELECT idemployee, nameemployee, surnameemployee, photo FROM employee WHERE idschool = ?");
|
||||||
|
$stT->execute([$idschool]);
|
||||||
|
foreach ($stT->fetchAll() as $t) {
|
||||||
$teachersById[(int) $t['idemployee']] = $t;
|
$teachersById[(int) $t['idemployee']] = $t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Indirizzo della scuola (da schools), al posto del testo fisso
|
||||||
|
$schoolAddress = implode(', ', array_filter([
|
||||||
|
trim((string) ($schoolData['address'] ?? '')),
|
||||||
|
trim((string) ($schoolData['city'] ?? '')),
|
||||||
|
]));
|
||||||
|
|
||||||
if (isset($_GET['prev_month'])) {
|
if (isset($_GET['prev_month'])) {
|
||||||
$currentMonthStart = preg_replace('/[^0-9\-]/', '', $_GET['prev_month']) . '-01';
|
$currentMonthStart = preg_replace('/[^0-9\-]/', '', $_GET['prev_month']) . '-01';
|
||||||
} elseif (isset($_GET['next_month'])) {
|
} elseif (isset($_GET['next_month'])) {
|
||||||
@@ -56,9 +64,10 @@ $sqlSchedule = "SELECT serviceschedule.*, service.servicename, service.colorclas
|
|||||||
FROM serviceschedule
|
FROM serviceschedule
|
||||||
LEFT JOIN service ON serviceschedule.idservice = service.idservice
|
LEFT JOIN service ON serviceschedule.idservice = service.idservice
|
||||||
WHERE serviceschedule.dateschedule BETWEEN :start AND DATE_ADD(:end, INTERVAL 1 DAY)
|
WHERE serviceschedule.dateschedule BETWEEN :start AND DATE_ADD(:end, INTERVAL 1 DAY)
|
||||||
|
AND serviceschedule.idschool = :idschool
|
||||||
ORDER BY serviceschedule.dateschedule";
|
ORDER BY serviceschedule.dateschedule";
|
||||||
$stmtSchedule = $pdo->prepare($sqlSchedule);
|
$stmtSchedule = $pdo->prepare($sqlSchedule);
|
||||||
$stmtSchedule->execute([':start' => $currentMonthStart, ':end' => $currentMonthEnd]);
|
$stmtSchedule->execute([':start' => $currentMonthStart, ':end' => $currentMonthEnd, ':idschool' => $idschool]);
|
||||||
$scheduleRows = $stmtSchedule->fetchAll();
|
$scheduleRows = $stmtSchedule->fetchAll();
|
||||||
|
|
||||||
// Tipologie di classe presenti nel mese (per la barra filtri), con relativo colore
|
// Tipologie di classe presenti nel mese (per la barra filtri), con relativo colore
|
||||||
@@ -81,11 +90,12 @@ if (!empty($scheduleIds)) {
|
|||||||
auth_users.first_name, auth_users.last_name, auth_users.id AS iduser
|
auth_users.first_name, auth_users.last_name, auth_users.id AS iduser
|
||||||
FROM bookingclass
|
FROM bookingclass
|
||||||
LEFT JOIN auth_users ON bookingclass.iduser = auth_users.id
|
LEFT JOIN auth_users ON bookingclass.iduser = auth_users.id
|
||||||
WHERE bookingclass.idserviceschedule IN ($ph)
|
WHERE bookingclass.idserviceschedule IN ($ph)
|
||||||
|
AND bookingclass.idschool = ?
|
||||||
AND bookingclass.status IN ('booked', 'pending', 'waiting')
|
AND bookingclass.status IN ('booked', 'pending', 'waiting')
|
||||||
ORDER BY bookingclass.created_at, auth_users.last_name, auth_users.first_name";
|
ORDER BY bookingclass.created_at, auth_users.last_name, auth_users.first_name";
|
||||||
$stmtBookings = $pdo->prepare($sqlBookings);
|
$stmtBookings = $pdo->prepare($sqlBookings);
|
||||||
$stmtBookings->execute(array_values($scheduleIds));
|
$stmtBookings->execute(array_merge(array_values($scheduleIds), [$idschool]));
|
||||||
foreach ($stmtBookings->fetchAll() as $b) {
|
foreach ($stmtBookings->fetchAll() as $b) {
|
||||||
$bookingsBySchedule[(int) $b['idserviceschedule']][] = $b;
|
$bookingsBySchedule[(int) $b['idserviceschedule']][] = $b;
|
||||||
}
|
}
|
||||||
@@ -535,7 +545,7 @@ $italianMonths = [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<?php include('include/languageselection.php'); ?>
|
<?php include('include/schoolswitcher.php'); ?><?php include('include/languageselection.php'); ?>
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
<?php include('include/profiletopbar.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -563,6 +573,8 @@ $italianMonths = [
|
|||||||
'3' => ['success', 'Lezione riprogrammata con successo.'],
|
'3' => ['success', 'Lezione riprogrammata con successo.'],
|
||||||
'4' => ['success', 'Classe eliminata con successo.'],
|
'4' => ['success', 'Classe eliminata con successo.'],
|
||||||
'5' => ['success', 'Prenotazione confermata con successo.'],
|
'5' => ['success', 'Prenotazione confermata con successo.'],
|
||||||
|
'6' => ['success', 'Partecipante rimosso dalla classe.'],
|
||||||
|
'added' => ['success', 'Partecipante aggiunto alla classe.'],
|
||||||
];
|
];
|
||||||
$m = $msgMap[$_GET['success']] ?? null;
|
$m = $msgMap[$_GET['success']] ?? null;
|
||||||
if ($m) : ?>
|
if ($m) : ?>
|
||||||
@@ -575,6 +587,8 @@ $italianMonths = [
|
|||||||
'duplicate' => 'Questo utente è già prenotato in questa classe.',
|
'duplicate' => 'Questo utente è già prenotato in questa classe.',
|
||||||
'insert' => 'Errore durante l\'inserimento. Riprova.',
|
'insert' => 'Errore durante l\'inserimento. Riprova.',
|
||||||
'missingdata' => 'Dati mancanti per l\'inserimento.',
|
'missingdata' => 'Dati mancanti per l\'inserimento.',
|
||||||
|
'notfound' => 'Elemento non trovato in questa scuola.',
|
||||||
|
'delete' => 'Errore durante l\'eliminazione. Riprova.',
|
||||||
];
|
];
|
||||||
$em = $errMap[$_GET['error']] ?? 'Si è verificato un errore.';
|
$em = $errMap[$_GET['error']] ?? 'Si è verificato un errore.';
|
||||||
?>
|
?>
|
||||||
@@ -649,7 +663,9 @@ $italianMonths = [
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</h3>
|
</h3>
|
||||||
<p class="class-meta"><i class="far fa-clock me-1"></i><?php echo e($whenFmt); ?></p>
|
<p class="class-meta"><i class="far fa-clock me-1"></i><?php echo e($whenFmt); ?></p>
|
||||||
<p class="class-meta"><i class="fas fa-location-dot me-1"></i>via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
<?php if ($schoolAddress !== '') : ?>
|
||||||
|
<p class="class-meta"><i class="fas fa-location-dot me-1"></i><?php echo e($schoolAddress); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
<?php if ($showTeacher) :
|
<?php if ($showTeacher) :
|
||||||
$tch = $teachersById[(int) ($sch['idteacher'] ?? 0)] ?? null; ?>
|
$tch = $teachersById[(int) ($sch['idteacher'] ?? 0)] ?? null; ?>
|
||||||
<p class="class-meta class-teacher">
|
<p class="class-meta class-teacher">
|
||||||
@@ -669,7 +685,7 @@ $italianMonths = [
|
|||||||
|
|
||||||
<div class="class-toolbar">
|
<div class="class-toolbar">
|
||||||
<button class="btn-soft btn-bookings" onclick="togglePanel(this)"><i class="fas fa-list-ul me-1"></i> Vedi prenotazioni</button>
|
<button class="btn-soft btn-bookings" onclick="togglePanel(this)"><i class="fas fa-list-ul me-1"></i> Vedi prenotazioni</button>
|
||||||
<button class="btn-soft btn-delete-class" onclick="confirmDeleteClass(<?php echo $scheduleId; ?>, '<?php echo e($sch['servicename']); ?>', '<?php echo e($whenFmt); ?>', <?php echo $countPersons; ?>)"><i class="fas fa-trash me-1"></i> Elimina classe</button>
|
<?php if ($isschooladmin) : ?><button class="btn-soft btn-delete-class" onclick="confirmDeleteClass(<?php echo $scheduleId; ?>, '<?php echo e($sch['servicename']); ?>', '<?php echo e($whenFmt); ?>', <?php echo $countPersons; ?>)"><i class="fas fa-trash me-1"></i> Elimina classe</button><?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bookings-panel">
|
<div class="bookings-panel">
|
||||||
|
|||||||
@@ -5,30 +5,40 @@ require_once('include/headscript.php');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Segna una prenotazione come "persa" (lostlesson = 'Y').
|
* Segna una prenotazione come "persa" (lostlesson = 'Y').
|
||||||
|
* POST: idbookingclass. Risposta JSON. Solo staff, solo scuola corrente.
|
||||||
*/
|
*/
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
function jsonOut(array $payload): void
|
function jsonOut(array $payload, int $code = 200): void
|
||||||
{
|
{
|
||||||
if (ob_get_length() !== false) {
|
if (ob_get_length() !== false) {
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
}
|
}
|
||||||
|
http_response_code($code);
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SchoolContext::isStaff()) {
|
||||||
|
jsonOut(['success' => false, 'error' => 'Accesso non autorizzato.'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
$idbookingclass = isset($_POST['idbookingclass']) ? (int) $_POST['idbookingclass'] : 0;
|
$idbookingclass = isset($_POST['idbookingclass']) ? (int) $_POST['idbookingclass'] : 0;
|
||||||
|
|
||||||
if ($idbookingclass <= 0) {
|
if ($idbookingclass <= 0) {
|
||||||
jsonOut(['success' => false, 'error' => 'ID prenotazione non valido.']);
|
jsonOut(['success' => false, 'error' => 'ID prenotazione non valido.'], 400);
|
||||||
|
}
|
||||||
|
if (!SchoolScope::belongs('bookingclass', $idbookingclass)) {
|
||||||
|
jsonOut(['success' => false, 'error' => 'Prenotazione non trovata in questa scuola.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $pdo->prepare("UPDATE bookingclass SET lostlesson = 'Y' WHERE idbookingclass = :id");
|
$stmt = $pdo->prepare("UPDATE bookingclass SET lostlesson = 'Y' WHERE idbookingclass = :id AND idschool = :idschool");
|
||||||
$stmt->execute([':id' => $idbookingclass]);
|
$stmt->execute([':id' => $idbookingclass, ':idschool' => $idschool]);
|
||||||
|
|
||||||
jsonOut(['success' => true]);
|
jsonOut(['success' => true]);
|
||||||
} catch (Throwable $ex) {
|
} catch (Throwable $ex) {
|
||||||
error_log('aggiorna_campo_lost error: ' . $ex->getMessage());
|
error_log('aggiorna_campo_lost error: ' . $ex->getMessage());
|
||||||
jsonOut(['success' => false, 'error' => 'Errore durante l\'aggiornamento.']);
|
jsonOut(['success' => false, 'error' => 'Errore durante il salvataggio.'], 500);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/bootstrap.php';
|
require_once __DIR__ . '/bootstrap.php';
|
||||||
|
require_once __DIR__ . '/school.php';
|
||||||
require_once dirname(__DIR__) . '/include/event_mailer.php';
|
require_once dirname(__DIR__) . '/include/event_mailer.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endpoint pubblico PRENOTAZIONE (POST).
|
* Endpoint pubblico PRENOTAZIONE (POST) per un evento di UNA scuola.
|
||||||
* Riceve i dati dal widget WordPress e crea la prenotazione.
|
* Riceve i dati dal widget WordPress e crea la prenotazione.
|
||||||
*
|
*
|
||||||
* Campi attesi (POST form-encoded o JSON):
|
* Campi attesi (POST form-encoded o JSON):
|
||||||
* event_id, name, surname, email, seats, consent (1), marketing (1|0)
|
* school_key, event_id, name, surname, email, seats, consent (1), marketing (1|0)
|
||||||
* website -> honeypot anti-spam (deve restare vuoto)
|
* website -> honeypot anti-spam (deve restare vuoto)
|
||||||
*
|
*
|
||||||
* Logica posti (conferma immediata):
|
* Logica posti (conferma immediata):
|
||||||
@@ -16,8 +17,7 @@ require_once dirname(__DIR__) . '/include/event_mailer.php';
|
|||||||
* - evento pieno + lista d'attesa OFF -> errore sold_out
|
* - evento pieno + lista d'attesa OFF -> errore sold_out
|
||||||
* - 0 < rimanenti < seats -> errore 'partial' (avvisa: solo N posti)
|
* - 0 < rimanenti < seats -> errore 'partial' (avvisa: solo N posti)
|
||||||
*
|
*
|
||||||
* Anti-oversell: transazione + lock della riga evento (SELECT ... FOR UPDATE),
|
* Anti-oversell: transazione + lock della riga evento (SELECT ... FOR UPDATE).
|
||||||
* così due prenotazioni simultanee non sforano la capienza.
|
|
||||||
*/
|
*/
|
||||||
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
|
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
|
||||||
send_json(['ok' => false, 'code' => 'method', 'error' => 'Metodo non consentito.'], 405);
|
send_json(['ok' => false, 'code' => 'method', 'error' => 'Metodo non consentito.'], 405);
|
||||||
@@ -52,6 +52,9 @@ $marketing = (!empty($in['marketing']) && $in['marketing'] !== '0') ? 'Y' : 'N';
|
|||||||
if ($eventId <= 0 || $name === '' || $surname === '') {
|
if ($eventId <= 0 || $name === '' || $surname === '') {
|
||||||
send_json(['ok' => false, 'code' => 'invalid', 'error' => 'Compila nome, cognome ed evento.'], 400);
|
send_json(['ok' => false, 'code' => 'invalid', 'error' => 'Compila nome, cognome ed evento.'], 400);
|
||||||
}
|
}
|
||||||
|
if (mb_strlen($name) > 100 || mb_strlen($surname) > 100) {
|
||||||
|
send_json(['ok' => false, 'code' => 'invalid', 'error' => 'Nome o cognome troppo lunghi.'], 400);
|
||||||
|
}
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
send_json(['ok' => false, 'code' => 'invalid', 'error' => 'Email non valida.'], 400);
|
send_json(['ok' => false, 'code' => 'invalid', 'error' => 'Email non valida.'], 400);
|
||||||
}
|
}
|
||||||
@@ -64,12 +67,18 @@ if ($seats < 1) {
|
|||||||
|
|
||||||
$pdo = pdo_conn();
|
$pdo = pdo_conn();
|
||||||
|
|
||||||
|
$school = yse_school_from_key($pdo, (string) ($in['school_key'] ?? ''));
|
||||||
|
if (!$school) {
|
||||||
|
send_json(['ok' => false, 'code' => 'not_available', 'error' => 'Evento non disponibile.'], 404);
|
||||||
|
}
|
||||||
|
$idschool = (int) $school['idschool'];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$pdo->beginTransaction();
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
// Lock della riga evento: serializza le prenotazioni dello stesso evento
|
// Lock della riga evento (solo se è della scuola): serializza le prenotazioni dello stesso evento
|
||||||
$es = $pdo->prepare("SELECT * FROM events WHERE id = ? FOR UPDATE");
|
$es = $pdo->prepare("SELECT * FROM events WHERE id = ? AND idschool = ? FOR UPDATE");
|
||||||
$es->execute([$eventId]);
|
$es->execute([$eventId, $idschool]);
|
||||||
$event = $es->fetch(PDO::FETCH_ASSOC);
|
$event = $es->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (!$event || $event['status'] !== 'published') {
|
if (!$event || $event['status'] !== 'published') {
|
||||||
@@ -90,17 +99,17 @@ try {
|
|||||||
if ($seats > $maxPerBooking) {
|
if ($seats > $maxPerBooking) {
|
||||||
$pdo->rollBack();
|
$pdo->rollBack();
|
||||||
send_json([
|
send_json([
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'code' => 'too_many',
|
'code' => 'too_many',
|
||||||
'max' => $maxPerBooking,
|
'max' => $maxPerBooking,
|
||||||
'error' => "Puoi prenotare al massimo {$maxPerBooking} posti per prenotazione."
|
'error' => "Puoi prenotare al massimo {$maxPerBooking} posti per prenotazione.",
|
||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Posti occupati (solo confermate/pending): protetto dal lock evento
|
// Posti occupati (confermate/pending/offerte): protetto dal lock evento
|
||||||
$os = $pdo->prepare("SELECT COALESCE(SUM(seats),0) FROM event_bookings
|
$os = $pdo->prepare("SELECT COALESCE(SUM(seats),0) FROM event_bookings
|
||||||
WHERE event_id = ? AND status IN ('confirmed','pending','offered')");
|
WHERE event_id = ? AND idschool = ? AND status IN ('confirmed','pending','offered')");
|
||||||
$os->execute([$eventId]);
|
$os->execute([$eventId, $idschool]);
|
||||||
$occupied = (int) $os->fetchColumn();
|
$occupied = (int) $os->fetchColumn();
|
||||||
$remaining = max(0, $maxSeats - $occupied);
|
$remaining = max(0, $maxSeats - $occupied);
|
||||||
|
|
||||||
@@ -123,11 +132,11 @@ try {
|
|||||||
], 409);
|
], 409);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token univoco per gestione/disdetta da link email
|
// Token univoco (globale) per gestione/disdetta da link email
|
||||||
$token = '';
|
$token = '';
|
||||||
|
$ck = $pdo->prepare("SELECT 1 FROM event_bookings WHERE token = ? LIMIT 1");
|
||||||
for ($i = 0; $i < 5; $i++) {
|
for ($i = 0; $i < 5; $i++) {
|
||||||
$candidate = bin2hex(random_bytes(16));
|
$candidate = bin2hex(random_bytes(16));
|
||||||
$ck = $pdo->prepare("SELECT 1 FROM event_bookings WHERE token = ? LIMIT 1");
|
|
||||||
$ck->execute([$candidate]);
|
$ck->execute([$candidate]);
|
||||||
if (!$ck->fetchColumn()) {
|
if (!$ck->fetchColumn()) {
|
||||||
$token = $candidate;
|
$token = $candidate;
|
||||||
@@ -142,12 +151,13 @@ try {
|
|||||||
$fullName = trim($name . ' ' . $surname);
|
$fullName = trim($name . ' ' . $surname);
|
||||||
|
|
||||||
$ins = $pdo->prepare("INSERT INTO event_bookings
|
$ins = $pdo->prepare("INSERT INTO event_bookings
|
||||||
(event_id, user_id, name, email, phone, seats, status, amount, token,
|
(idschool, event_id, user_id, name, email, phone, seats, status, amount, token,
|
||||||
consent_at, marketing_opt_in, created_at, updated_at)
|
consent_at, marketing_opt_in, created_at, updated_at)
|
||||||
VALUES
|
VALUES
|
||||||
(:event_id, NULL, :name, :email, NULL, :seats, :status, :amount, :token,
|
(:idschool, :event_id, NULL, :name, :email, NULL, :seats, :status, :amount, :token,
|
||||||
NOW(), :marketing, NOW(), NOW())");
|
NOW(), :marketing, NOW(), NOW())");
|
||||||
$ins->execute([
|
$ins->execute([
|
||||||
|
':idschool' => $idschool,
|
||||||
':event_id' => $eventId,
|
':event_id' => $eventId,
|
||||||
':name' => $fullName,
|
':name' => $fullName,
|
||||||
':email' => $email,
|
':email' => $email,
|
||||||
@@ -159,27 +169,6 @@ try {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$pdo->commit();
|
$pdo->commit();
|
||||||
|
|
||||||
// Email di conferma / lista d'attesa (best-effort: non blocca la prenotazione)
|
|
||||||
try {
|
|
||||||
$bookingRow = ['email' => $email, 'name' => $fullName, 'seats' => $seats, 'status' => $status, 'token' => $token];
|
|
||||||
yse_mail_booking($bookingRow, $event);
|
|
||||||
} catch (Throwable $mailEx) {
|
|
||||||
error_log('[book mail] ' . $mailEx->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$msg = $status === 'confirmed'
|
|
||||||
? 'Prenotazione confermata! Ti abbiamo inviato una email di riepilogo.'
|
|
||||||
: "Sei in lista d'attesa: ti avviseremo appena si libera un posto.";
|
|
||||||
|
|
||||||
send_json([
|
|
||||||
'ok' => true,
|
|
||||||
'status' => $status,
|
|
||||||
'seats' => $seats,
|
|
||||||
'amount' => $amount,
|
|
||||||
'token' => $token,
|
|
||||||
'message' => $msg,
|
|
||||||
]);
|
|
||||||
} catch (Throwable $ex) {
|
} catch (Throwable $ex) {
|
||||||
if ($pdo->inTransaction()) {
|
if ($pdo->inTransaction()) {
|
||||||
$pdo->rollBack();
|
$pdo->rollBack();
|
||||||
@@ -187,3 +176,20 @@ try {
|
|||||||
error_log('[apiwp/book] ' . $ex->getMessage());
|
error_log('[apiwp/book] ' . $ex->getMessage());
|
||||||
send_json(['ok' => false, 'code' => 'server', 'error' => 'Errore durante la prenotazione. Riprova.'], 500);
|
send_json(['ok' => false, 'code' => 'server', 'error' => 'Errore durante la prenotazione. Riprova.'], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Email di conferma / lista d'attesa (best-effort: non lancia eccezioni)
|
||||||
|
$bookingRow = ['email' => $email, 'name' => $fullName, 'seats' => $seats, 'status' => $status, 'token' => $token];
|
||||||
|
yse_mail_booking($bookingRow, $event);
|
||||||
|
|
||||||
|
$msg = $status === 'confirmed'
|
||||||
|
? 'Prenotazione confermata! Ti abbiamo inviato una email di riepilogo.'
|
||||||
|
: "Sei in lista d'attesa: ti avviseremo appena si libera un posto.";
|
||||||
|
|
||||||
|
send_json([
|
||||||
|
'ok' => true,
|
||||||
|
'status' => $status,
|
||||||
|
'seats' => $seats,
|
||||||
|
'amount' => $amount,
|
||||||
|
'token' => $token,
|
||||||
|
'message' => $msg,
|
||||||
|
]);
|
||||||
|
|||||||
@@ -1,44 +1,64 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap per gli endpoint PUBBLICI del modulo Eventi (cartella /api).
|
* Bootstrap per gli endpoint PUBBLICI del modulo Eventi (cartella /apiwp).
|
||||||
* NON include headscript.php: niente login/redirect. Serve solo il DB.
|
* NON include headscript.php: niente login/redirect. Serve solo il DB.
|
||||||
*
|
*
|
||||||
* Posiziona la cartella /api allo stesso livello di events.php, class/, include/.
|
* CORS: sono ammessi i domini dichiarati dalle scuole attive in
|
||||||
* Requisito: class/db-functions.php (DBHandlerSelect) già presente e autonomo.
|
* schools.widget_origins (Opzioni Eventi → Sito WordPress).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Path assoluto a DBHandlerSelect (api/ -> ../class/db-functions.php)
|
|
||||||
require_once dirname(__DIR__) . '/class/db-functions.php';
|
require_once dirname(__DIR__) . '/class/db-functions.php';
|
||||||
|
|
||||||
// URL pubblico di yogibook: usato per rendere assoluti i path delle immagini.
|
|
||||||
if (!defined('YB_PUBLIC_BASE')) {
|
|
||||||
define('YB_PUBLIC_BASE', 'https://yogibook.yogasoul.it/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Domini WordPress autorizzati (per la prenotazione via browser).
|
|
||||||
$YB_ALLOWED_ORIGINS = ['https://yogasoul.it', 'https://www.yogasoul.it'];
|
|
||||||
|
|
||||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
|
||||||
if ($origin !== '' && in_array($origin, $YB_ALLOWED_ORIGINS, true)) {
|
|
||||||
header('Access-Control-Allow-Origin: ' . $origin);
|
|
||||||
header('Vary: Origin');
|
|
||||||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
|
||||||
header('Access-Control-Allow-Headers: Content-Type');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preflight CORS
|
|
||||||
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'OPTIONS') {
|
|
||||||
http_response_code(204);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
function pdo_conn(): PDO
|
function pdo_conn(): PDO
|
||||||
{
|
{
|
||||||
return DBHandlerSelect::getInstance()->getConnection();
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rende assoluto un path immagine relativo (es. assets/uploads/events/x.jpg). */
|
// La connessione carica anche il .env (APP_URL, MAIL_*, YSE_CRON_KEY)
|
||||||
|
pdo_conn();
|
||||||
|
|
||||||
|
// URL pubblico di YogiBook: usato per rendere assoluti i path delle immagini.
|
||||||
|
if (!defined('YB_PUBLIC_BASE')) {
|
||||||
|
define('YB_PUBLIC_BASE', rtrim($_ENV['APP_URL'] ?? 'https://yogibook.yogasoul.it', '/') . '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** "https://Sito.it:443/qualcosa" -> "https://sito.it:443" ('' se non valida) */
|
||||||
|
function yb_normalize_origin(string $origin): string
|
||||||
|
{
|
||||||
|
$p = parse_url(trim($origin));
|
||||||
|
if (!$p || empty($p['scheme']) || empty($p['host'])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$scheme = strtolower($p['scheme']);
|
||||||
|
if (!in_array($scheme, ['http', 'https'], true)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return $scheme . '://' . strtolower($p['host']) . (isset($p['port']) ? ':' . (int) $p['port'] : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** L'origine appartiene a una scuola attiva? */
|
||||||
|
function yb_origin_allowed(string $origin): bool
|
||||||
|
{
|
||||||
|
$o = yb_normalize_origin($origin);
|
||||||
|
if ($o === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$st = pdo_conn()->prepare(
|
||||||
|
"SELECT 1 FROM schools
|
||||||
|
WHERE status <> 'suspended' AND FIND_IN_SET(?, widget_origins) > 0
|
||||||
|
LIMIT 1"
|
||||||
|
);
|
||||||
|
$st->execute([$o]);
|
||||||
|
return (bool) $st->fetchColumn();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log('[apiwp/bootstrap] CORS: ' . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rende assoluto un path immagine relativo (es. uploads/schools/1/events/x.jpg). */
|
||||||
function public_url(?string $rel): ?string
|
function public_url(?string $rel): ?string
|
||||||
{
|
{
|
||||||
if ($rel === null || $rel === '') {
|
if ($rel === null || $rel === '') {
|
||||||
@@ -61,3 +81,18 @@ function send_json($data, int $code = 200): void
|
|||||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- CORS ---------------------------------------------------------------
|
||||||
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||||
|
if ($origin !== '' && yb_origin_allowed($origin)) {
|
||||||
|
header('Access-Control-Allow-Origin: ' . $origin);
|
||||||
|
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||||||
|
header('Access-Control-Allow-Headers: Content-Type');
|
||||||
|
}
|
||||||
|
header('Vary: Origin');
|
||||||
|
|
||||||
|
// Preflight CORS
|
||||||
|
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'OPTIONS') {
|
||||||
|
http_response_code(204);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/bootstrap.php';
|
require_once __DIR__ . '/bootstrap.php';
|
||||||
require_once dirname(__DIR__) . '/include/event_waitlist.php';
|
require_once dirname(__DIR__) . '/include/event_waitlist.php';
|
||||||
require_once dirname(__DIR__) . '/include/event_mailer.php';
|
require_once dirname(__DIR__) . '/include/event_mailer.php'; // carica anche SchoolSettings e SchoolMail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRON unico del modulo Eventi. Da richiamare periodicamente (es. ogni 10 min).
|
* CRON unico del modulo Eventi, per TUTTE le scuole. Da richiamare periodicamente (es. ogni 10 min).
|
||||||
* Protezione: chiave segreta in .env (YSE_CRON_KEY) passata come ?key=...
|
* Protezione: chiave segreta in .env (YSE_CRON_KEY) passata come ?key=...
|
||||||
*
|
*
|
||||||
* Fa tre cose a ogni giro:
|
* Fa tre cose a ogni giro:
|
||||||
* 1) Pubblica gli eventi programmati arrivati alla data di apertura.
|
* 1) Pubblica gli eventi programmati arrivati alla data di apertura.
|
||||||
* 2) Invia i promemoria automatici (ore effettive per-evento o default), 1 sola volta.
|
* 2) Invia i promemoria automatici (ore per evento o default DELLA SUA SCUOLA), una sola volta.
|
||||||
* 3) Applica la scadenza delle offerte lista d'attesa (offered non riconfermati):
|
* 3) Applica la scadenza delle offerte lista d'attesa (offered non riconfermati):
|
||||||
* li annulla e offre il posto al prossimo in coda (email E).
|
* le annulla e offre il posto al prossimo in coda.
|
||||||
|
* Le scuole sospese vengono saltate nei punti 2 e 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$pdo = pdo_conn(); // carica anche il .env (per la chiave e le MAIL_*)
|
$pdo = pdo_conn(); // carica anche il .env (per la chiave e le MAIL_*)
|
||||||
@@ -22,105 +23,131 @@ if ($expected === '' || !hash_equals($expected, $provided)) {
|
|||||||
send_json(['ok' => false, 'error' => 'Forbidden'], 403);
|
send_json(['ok' => false, 'error' => 'Forbidden'], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@set_time_limit(600);
|
||||||
$report = ['published' => 0, 'reminders' => 0, 'offers_expired' => 0, 'promoted' => 0];
|
$report = ['published' => 0, 'reminders' => 0, 'offers_expired' => 0, 'promoted' => 0];
|
||||||
|
|
||||||
// Default scuola
|
/** Default eventi della scuola (cache per giro) */
|
||||||
$opt = [];
|
function cron_school_defaults(int $idschool): array
|
||||||
try {
|
{
|
||||||
$opt = $pdo->query("SELECT * FROM `option` LIMIT 1")->fetch(PDO::FETCH_ASSOC) ?: [];
|
static $cache = [];
|
||||||
} catch (Throwable $e) {
|
if (!isset($cache[$idschool])) {
|
||||||
$opt = [];
|
$cache[$idschool] = [
|
||||||
|
'rem_enabled' => SchoolSettings::get('event_reminder_enabled', 'N', $idschool) === 'Y',
|
||||||
|
'rem_hours' => (int) SchoolSettings::get('event_reminder_hours', 24, $idschool),
|
||||||
|
'offer_hours' => (int) SchoolSettings::get('event_offer_expiry_hours', 24, $idschool),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $cache[$idschool];
|
||||||
}
|
}
|
||||||
$defRemEnabled = ($opt['event_reminder_enabled'] ?? 'N') === 'Y';
|
|
||||||
$defRemHours = (int) ($opt['event_reminder_hours'] ?? 24);
|
|
||||||
$defOfferHours = (int) ($opt['event_offer_expiry_hours'] ?? 24);
|
|
||||||
|
|
||||||
/* 1) Pubblica gli eventi programmati arrivati a scadenza */
|
/* 1) Pubblica gli eventi programmati arrivati a scadenza (tutte le scuole) */
|
||||||
try {
|
try {
|
||||||
$pub = $pdo->prepare("UPDATE events SET status = 'published', updated_at = NOW()
|
$pub = $pdo->prepare("UPDATE events SET status = 'published', updated_at = NOW()
|
||||||
WHERE status = 'scheduled' AND publish_at IS NOT NULL AND publish_at <= NOW()");
|
WHERE status = 'scheduled' AND publish_at IS NOT NULL AND publish_at <= NOW()");
|
||||||
$pub->execute();
|
$pub->execute();
|
||||||
$report['published'] = $pub->rowCount();
|
$report['published'] = $pub->rowCount();
|
||||||
} catch (Throwable $e) {
|
} catch (PDOException $e) {
|
||||||
error_log('[cron publish] ' . $e->getMessage());
|
error_log('[cron publish] ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2) Promemoria automatici (una sola volta per evento) */
|
/* 2) Promemoria automatici (una sola volta per evento) */
|
||||||
try {
|
try {
|
||||||
$evs = $pdo->query("SELECT * FROM events
|
$evs = $pdo->query("SELECT e.* FROM events e
|
||||||
WHERE status = 'published' AND reminder_sent_at IS NULL AND starts_at > NOW()")
|
JOIN schools s ON s.idschool = e.idschool
|
||||||
|
WHERE e.status = 'published' AND e.reminder_sent_at IS NULL AND e.starts_at > NOW()
|
||||||
|
AND s.status <> 'suspended'")
|
||||||
->fetchAll(PDO::FETCH_ASSOC);
|
->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$claim = $pdo->prepare("UPDATE events SET reminder_sent_at = NOW()
|
||||||
|
WHERE id = ? AND idschool = ? AND reminder_sent_at IS NULL");
|
||||||
|
$ps = $pdo->prepare("SELECT * FROM event_bookings WHERE event_id = ? AND idschool = ? AND status = 'confirmed'");
|
||||||
|
|
||||||
foreach ($evs as $ev) {
|
foreach ($evs as $ev) {
|
||||||
$enabled = $ev['reminder_enabled'] !== null ? ($ev['reminder_enabled'] === 'Y') : $defRemEnabled;
|
$idschool = (int) $ev['idschool'];
|
||||||
|
$def = cron_school_defaults($idschool);
|
||||||
|
|
||||||
|
$enabled = $ev['reminder_enabled'] !== null ? ($ev['reminder_enabled'] === 'Y') : $def['rem_enabled'];
|
||||||
if (!$enabled) {
|
if (!$enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$hours = $ev['reminder_hours'] !== null ? (int) $ev['reminder_hours'] : $defRemHours;
|
$hours = $ev['reminder_hours'] !== null ? (int) $ev['reminder_hours'] : $def['rem_hours'];
|
||||||
if (strtotime($ev['starts_at']) - $hours * 3600 > time()) {
|
if (strtotime($ev['starts_at']) - $hours * 3600 > time()) {
|
||||||
continue; // non ancora l'ora del promemoria
|
continue; // non ancora l'ora del promemoria
|
||||||
}
|
}
|
||||||
$ps = $pdo->prepare("SELECT * FROM event_bookings WHERE event_id = ? AND status = 'confirmed'");
|
|
||||||
$ps->execute([$ev['id']]);
|
// "Prenoto" l'evento prima di inviare: se due cron si sovrappongono, uno solo invia
|
||||||
|
$claim->execute([(int) $ev['id'], $idschool]);
|
||||||
|
if ($claim->rowCount() === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ps->execute([(int) $ev['id'], $idschool]);
|
||||||
foreach ($ps->fetchAll(PDO::FETCH_ASSOC) as $p) {
|
foreach ($ps->fetchAll(PDO::FETCH_ASSOC) as $p) {
|
||||||
try {
|
if (yse_mail_reminder($p, $ev)) {
|
||||||
yse_mail_reminder($p, $ev);
|
|
||||||
$report['reminders']++;
|
$report['reminders']++;
|
||||||
} catch (Throwable $me) {
|
|
||||||
error_log('[cron reminder] ' . $me->getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pdo->prepare("UPDATE events SET reminder_sent_at = NOW() WHERE id = ?")->execute([$ev['id']]);
|
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} catch (PDOException $e) {
|
||||||
error_log('[cron reminders] ' . $e->getMessage());
|
error_log('[cron reminders] ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3) Scadenza offerte lista d'attesa */
|
/* 3) Scadenza offerte lista d'attesa */
|
||||||
try {
|
try {
|
||||||
$offers = $pdo->query("SELECT b.*, e.offer_expiry_hours AS ev_offer_hours
|
$offers = $pdo->query("SELECT b.*, e.offer_expiry_hours AS ev_offer_hours
|
||||||
FROM event_bookings b JOIN events e ON e.id = b.event_id
|
FROM event_bookings b
|
||||||
WHERE b.status = 'offered' AND b.offered_at IS NOT NULL")
|
JOIN events e ON e.id = b.event_id AND e.idschool = b.idschool
|
||||||
|
JOIN schools s ON s.idschool = b.idschool
|
||||||
|
WHERE b.status = 'offered' AND b.offered_at IS NOT NULL
|
||||||
|
AND s.status <> 'suspended'")
|
||||||
->fetchAll(PDO::FETCH_ASSOC);
|
->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
foreach ($offers as $o) {
|
foreach ($offers as $o) {
|
||||||
$hours = $o['ev_offer_hours'] !== null ? (int) $o['ev_offer_hours'] : $defOfferHours;
|
$idschool = (int) $o['idschool'];
|
||||||
|
$eventId = (int) $o['event_id'];
|
||||||
|
$def = cron_school_defaults($idschool);
|
||||||
|
|
||||||
|
$hours = $o['ev_offer_hours'] !== null ? (int) $o['ev_offer_hours'] : $def['offer_hours'];
|
||||||
if (strtotime($o['offered_at']) + $hours * 3600 > time()) {
|
if (strtotime($o['offered_at']) + $hours * 3600 > time()) {
|
||||||
continue; // offerta ancora valida
|
continue; // offerta ancora valida
|
||||||
}
|
}
|
||||||
|
|
||||||
$promoted = [];
|
$promoted = [];
|
||||||
try {
|
try {
|
||||||
$pdo->beginTransaction();
|
$pdo->beginTransaction();
|
||||||
$pdo->prepare("SELECT id FROM events WHERE id = ? FOR UPDATE")->execute([(int) $o['event_id']]);
|
$pdo->prepare("SELECT id FROM events WHERE id = ? AND idschool = ? FOR UPDATE")->execute([$eventId, $idschool]);
|
||||||
$st = $pdo->prepare("SELECT status FROM event_bookings WHERE id = ?");
|
$st = $pdo->prepare("SELECT status FROM event_bookings WHERE id = ? AND idschool = ?");
|
||||||
$st->execute([(int) $o['id']]);
|
$st->execute([(int) $o['id'], $idschool]);
|
||||||
if ($st->fetchColumn() === 'offered') {
|
if ($st->fetchColumn() === 'offered') {
|
||||||
$pdo->prepare("UPDATE event_bookings SET status = 'cancelled', updated_at = NOW() WHERE id = ?")
|
$pdo->prepare("UPDATE event_bookings SET status = 'cancelled', updated_at = NOW()
|
||||||
->execute([(int) $o['id']]);
|
WHERE id = ? AND idschool = ?")
|
||||||
$promoted = promoteFromWaitlist($pdo, (int) $o['event_id']);
|
->execute([(int) $o['id'], $idschool]);
|
||||||
|
$promoted = promoteFromWaitlist($pdo, $eventId);
|
||||||
$report['offers_expired']++;
|
$report['offers_expired']++;
|
||||||
}
|
}
|
||||||
$pdo->commit();
|
$pdo->commit();
|
||||||
|
} catch (PDOException $te) {
|
||||||
if (!empty($promoted)) {
|
|
||||||
$ev = $pdo->prepare("SELECT * FROM events WHERE id = ?");
|
|
||||||
$ev->execute([(int) $o['event_id']]);
|
|
||||||
$evRow = $ev->fetch(PDO::FETCH_ASSOC);
|
|
||||||
foreach ($promoted as $pr) {
|
|
||||||
try {
|
|
||||||
yse_mail_promotion($pr, $evRow);
|
|
||||||
$report['promoted']++;
|
|
||||||
} catch (Throwable $pe) {
|
|
||||||
error_log('[cron promo] ' . $pe->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable $te) {
|
|
||||||
if ($pdo->inTransaction()) {
|
if ($pdo->inTransaction()) {
|
||||||
$pdo->rollBack();
|
$pdo->rollBack();
|
||||||
}
|
}
|
||||||
error_log('[cron offer] ' . $te->getMessage());
|
error_log('[cron offer] ' . $te->getMessage());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($promoted)) {
|
||||||
|
$ev = $pdo->prepare("SELECT * FROM events WHERE id = ? AND idschool = ?");
|
||||||
|
$ev->execute([$eventId, $idschool]);
|
||||||
|
$evRow = $ev->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if ($evRow) {
|
||||||
|
foreach ($promoted as $pr) {
|
||||||
|
if (yse_mail_promotion($pr, $evRow)) {
|
||||||
|
$report['promoted']++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} catch (PDOException $e) {
|
||||||
error_log('[cron offers] ' . $e->getMessage());
|
error_log('[cron offers] ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,36 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/bootstrap.php';
|
require_once __DIR__ . '/bootstrap.php';
|
||||||
|
require_once __DIR__ . '/school.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endpoint pubblico LISTA eventi (sola lettura).
|
* Endpoint pubblico LISTA eventi (sola lettura) di UNA scuola.
|
||||||
* Ritorna gli eventi PUBBLICATI e NON ancora terminati, con posti/prezzo/gallery.
|
* Ritorna gli eventi pubblicati/programmati e non ancora terminati, con posti/prezzo/gallery.
|
||||||
*
|
*
|
||||||
* Parametri (query string):
|
* Parametri (query string):
|
||||||
|
* ?key=... -> chiave widget della scuola (obbligatoria dopo la fase di transizione)
|
||||||
* ?id=12 -> un solo evento
|
* ?id=12 -> un solo evento
|
||||||
* ?ids=12,15,20 -> solo questi eventi (nell'ordine per data)
|
* ?ids=12,15,20 -> solo questi eventi (nell'ordine per data)
|
||||||
* ?limit=3 -> massimo N eventi
|
* ?limit=3 -> massimo N eventi
|
||||||
* Senza parametri: tutti i pubblicati futuri, per data crescente.
|
* Senza id/ids: tutti gli eventi futuri della scuola, per data crescente.
|
||||||
*
|
*
|
||||||
* Regole di visibilità:
|
* Regole di visibilità:
|
||||||
* status = 'published' AND COALESCE(ends_at, starts_at) >= NOW()
|
* status IN ('published','scheduled') AND COALESCE(ends_at, starts_at) >= NOW()
|
||||||
* (l'evento sparisce da solo quando è terminato)
|
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
$pdo = pdo_conn();
|
$pdo = pdo_conn();
|
||||||
|
|
||||||
|
$school = yse_school_from_key($pdo, (string) ($_GET['key'] ?? ''));
|
||||||
|
if (!$school) {
|
||||||
|
send_json(['ok' => false, 'error' => 'Scuola non riconosciuta.'], 403);
|
||||||
|
}
|
||||||
|
$idschool = (int) $school['idschool'];
|
||||||
|
|
||||||
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
||||||
$idsParam = trim($_GET['ids'] ?? '');
|
$idsParam = trim((string) ($_GET['ids'] ?? ''));
|
||||||
$limit = isset($_GET['limit']) ? max(1, min(50, (int) $_GET['limit'])) : 0;
|
$limit = isset($_GET['limit']) ? max(1, min(50, (int) $_GET['limit'])) : 0;
|
||||||
|
|
||||||
$where = ["e.status IN ('published','scheduled')", "COALESCE(e.ends_at, e.starts_at) >= NOW()"];
|
$where = ['e.idschool = ?', "e.status IN ('published','scheduled')", 'COALESCE(e.ends_at, e.starts_at) >= NOW()'];
|
||||||
$params = [];
|
$params = [$idschool, $idschool, $idschool]; // 2 subquery + evento
|
||||||
|
|
||||||
if ($id > 0) {
|
if ($id > 0) {
|
||||||
$where[] = 'e.id = ?';
|
$where[] = 'e.id = ?';
|
||||||
@@ -49,12 +56,14 @@ try {
|
|||||||
LEFT JOIN auth_users u ON u.id = e.user_id
|
LEFT JOIN auth_users u ON u.id = e.user_id
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT event_id, SUM(seats) AS occupied
|
SELECT event_id, SUM(seats) AS occupied
|
||||||
FROM event_bookings WHERE status IN ('confirmed','pending','offered')
|
FROM event_bookings
|
||||||
|
WHERE idschool = ? AND status IN ('confirmed','pending','offered')
|
||||||
GROUP BY event_id
|
GROUP BY event_id
|
||||||
) b ON b.event_id = e.id
|
) b ON b.event_id = e.id
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT event_id, SUM(seats) AS waiting
|
SELECT event_id, SUM(seats) AS waiting
|
||||||
FROM event_bookings WHERE status = 'waiting'
|
FROM event_bookings
|
||||||
|
WHERE idschool = ? AND status = 'waiting'
|
||||||
GROUP BY event_id
|
GROUP BY event_id
|
||||||
) w ON w.event_id = e.id
|
) w ON w.event_id = e.id
|
||||||
WHERE " . implode(' AND ', $where) . "
|
WHERE " . implode(' AND ', $where) . "
|
||||||
@@ -100,7 +109,7 @@ try {
|
|||||||
'scheduled' => $r['status'] === 'scheduled',
|
'scheduled' => $r['status'] === 'scheduled',
|
||||||
'bookable' => $r['status'] === 'published',
|
'bookable' => $r['status'] === 'published',
|
||||||
'publish_at' => $r['publish_at'],
|
'publish_at' => $r['publish_at'],
|
||||||
'description' => $r['description'], // HTML (sanificare al rendering in WP)
|
'description' => $r['description'], // HTML: il plugin lo sanifica con wp_kses_post
|
||||||
'instructions' => $r['instructions'],
|
'instructions' => $r['instructions'],
|
||||||
'what_to_bring' => $r['what_to_bring'],
|
'what_to_bring' => $r['what_to_bring'],
|
||||||
'suitable_for' => $r['suitable_for'],
|
'suitable_for' => $r['suitable_for'],
|
||||||
@@ -126,8 +135,13 @@ try {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
send_json(['ok' => true, 'count' => count($events), 'events' => $events]);
|
send_json([
|
||||||
} catch (Throwable $ex) {
|
'ok' => true,
|
||||||
error_log('[api/events] ' . $ex->getMessage());
|
'school' => ['name' => $school['name']],
|
||||||
|
'count' => count($events),
|
||||||
|
'events' => $events,
|
||||||
|
]);
|
||||||
|
} catch (PDOException $ex) {
|
||||||
|
error_log('[apiwp/events] ' . $ex->getMessage());
|
||||||
send_json(['ok' => false, 'error' => 'Errore nel recupero degli eventi.'], 500);
|
send_json(['ok' => false, 'error' => 'Errore nel recupero degli eventi.'], 500);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scuola per gli endpoint pubblici WordPress (senza sessione).
|
||||||
|
*
|
||||||
|
* events.php e book.php ricevono la chiave widget della scuola (schools.widget_key)
|
||||||
|
* dal plugin: ?key=... per la lista, school_key nel POST per la prenotazione.
|
||||||
|
* cancel.php, confirm.php e cron_reminders.php non la usano: la scuola si ricava
|
||||||
|
* dalla prenotazione o dall'evento.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('YSE_FALLBACK_SCHOOL')) {
|
||||||
|
// TEMPORANEO: plugin non ancora aggiornato (nessuna chiave) -> Seregno.
|
||||||
|
// Da togliere quando tutti i siti WordPress passano la chiave.
|
||||||
|
define('YSE_FALLBACK_SCHOOL', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('yse_school_from_key')) {
|
||||||
|
/** Riga `schools` attiva per la chiave, o null se non valida */
|
||||||
|
function yse_school_from_key(PDO $pdo, string $key): ?array
|
||||||
|
{
|
||||||
|
$key = strtolower(trim($key));
|
||||||
|
|
||||||
|
if ($key === '') {
|
||||||
|
$st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ? AND status <> 'suspended'");
|
||||||
|
$st->execute([YSE_FALLBACK_SCHOOL]);
|
||||||
|
return $st->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-f0-9]{32}$/', $key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT * FROM schools WHERE widget_key = ? AND status <> 'suspended'");
|
||||||
|
$st->execute([$key]);
|
||||||
|
return $st->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,498 @@
|
|||||||
|
/* YogiBook - pagine abbonamento piattaforma (superadmin e scuola) */
|
||||||
|
.admin-card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
|
||||||
|
margin-bottom: 22px;
|
||||||
|
}
|
||||||
|
.admin-card .card-body {
|
||||||
|
padding: 26px 30px;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #1e4a4f;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.section-title .disc {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #6fbabe;
|
||||||
|
box-shadow: 5px 0 0 #dbf6f9;
|
||||||
|
margin-right: 14px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.section-lead {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.list-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
.form-label,
|
||||||
|
.admin-card label {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
.form-control,
|
||||||
|
.form-select {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #e2e4e9;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
.form-control:focus,
|
||||||
|
.form-select:focus {
|
||||||
|
border-color: #2f7f84;
|
||||||
|
box-shadow: 0 0 0 3px rgba(47, 127, 132, 0.14);
|
||||||
|
}
|
||||||
|
.form-check-input:checked {
|
||||||
|
background-color: #2f7f84;
|
||||||
|
border-color: #2f7f84;
|
||||||
|
}
|
||||||
|
.hint {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.os-divider {
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
margin: 24px 0 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-yb {
|
||||||
|
background: #2f7f84;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 9px 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.btn-yb:hover,
|
||||||
|
.btn-yb:focus {
|
||||||
|
background: #1e4a4f;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.btn-yb:disabled {
|
||||||
|
background: #b9c7c8;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.btn-act {
|
||||||
|
border: 1px solid #e2e4e9;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.btn-act:hover {
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: #111827;
|
||||||
|
}
|
||||||
|
.btn-act.ok {
|
||||||
|
color: #1a7f52;
|
||||||
|
border-color: #b9e4cc;
|
||||||
|
}
|
||||||
|
.btn-act.ok:hover {
|
||||||
|
background: #e7f7ee;
|
||||||
|
}
|
||||||
|
.btn-act.danger {
|
||||||
|
color: #c0392b;
|
||||||
|
border-color: #f2c9c4;
|
||||||
|
}
|
||||||
|
.btn-act.danger:hover {
|
||||||
|
background: #fdecea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yb-table thead th {
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
color: #6b7280;
|
||||||
|
border-bottom: 2px solid #eef0f3;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.yb-table td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.yb-table .sub {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.yb-table tr.detail td {
|
||||||
|
background: #fafbfc;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
.mono {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||||
|
}
|
||||||
|
.code-chip {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #1e4a4f;
|
||||||
|
background: #dbf6f9;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.pill.ok {
|
||||||
|
background: #e7f7ee;
|
||||||
|
color: #1a7f52;
|
||||||
|
}
|
||||||
|
.pill.warn {
|
||||||
|
background: #fff4e0;
|
||||||
|
color: #92560b;
|
||||||
|
}
|
||||||
|
.pill.danger {
|
||||||
|
background: #fdecea;
|
||||||
|
color: #b03a2e;
|
||||||
|
}
|
||||||
|
.pill.info {
|
||||||
|
background: #e6f4f5;
|
||||||
|
color: #1e4a4f;
|
||||||
|
}
|
||||||
|
.pill.muted {
|
||||||
|
background: #eef0f3;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpis {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 22px;
|
||||||
|
}
|
||||||
|
.kpi {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 16px 18px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
display: block;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
.kpi:hover {
|
||||||
|
color: inherit;
|
||||||
|
border-color: #dbf6f9;
|
||||||
|
}
|
||||||
|
.kpi.on {
|
||||||
|
border-color: #6fbabe;
|
||||||
|
}
|
||||||
|
.kpi .n {
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1e4a4f;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
.kpi .l {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filters {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
.filters .form-select,
|
||||||
|
.filters .form-control {
|
||||||
|
min-width: 170px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 10px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
.empty-state i {
|
||||||
|
font-size: 34px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: block;
|
||||||
|
color: #cfe3e4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.info-box i {
|
||||||
|
font-size: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
.info-box.warn {
|
||||||
|
background: #fff8ec;
|
||||||
|
border: 1px solid #eed9b7;
|
||||||
|
color: #6b4b1e;
|
||||||
|
}
|
||||||
|
.info-box.ok {
|
||||||
|
background: #f2fbf6;
|
||||||
|
border: 1px solid #b9e4cc;
|
||||||
|
color: #1a5c3d;
|
||||||
|
}
|
||||||
|
.info-box.info {
|
||||||
|
background: #f4fafa;
|
||||||
|
border: 1px solid #cfe5e6;
|
||||||
|
color: #1e4a4f;
|
||||||
|
}
|
||||||
|
.info-box.danger {
|
||||||
|
background: #fdf1ef;
|
||||||
|
border: 1px solid #f2c9c4;
|
||||||
|
color: #8f2f24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kv {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(130px, auto) 1fr;
|
||||||
|
gap: 6px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.kv dt {
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.kv dd {
|
||||||
|
margin: 0;
|
||||||
|
color: #1f2937;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.copy-row input {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
background: #fafbfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pagina abbonamento scuola */
|
||||||
|
.sub-hero {
|
||||||
|
display: flex;
|
||||||
|
gap: 22px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.sub-hero .big {
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1e4a4f;
|
||||||
|
line-height: 1.15;
|
||||||
|
}
|
||||||
|
.sub-hero .days {
|
||||||
|
min-width: 120px;
|
||||||
|
text-align: center;
|
||||||
|
background: #f4fafa;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
.sub-hero .days b {
|
||||||
|
display: block;
|
||||||
|
font-size: 30px;
|
||||||
|
color: #1e4a4f;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.sub-hero .days span {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.cycle-toggle {
|
||||||
|
display: inline-flex;
|
||||||
|
background: #eef3f3;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 4px;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.cycle-toggle label {
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 7px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #4b5563;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cycle-toggle input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.cycle-toggle label.active {
|
||||||
|
background: #fff;
|
||||||
|
color: #1e4a4f;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
.plan-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.plan-card {
|
||||||
|
position: relative;
|
||||||
|
border: 2px solid #e2e4e9;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
background: #fff;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.plan-card input {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.plan-card.sel {
|
||||||
|
border-color: #2f7f84;
|
||||||
|
background: #f4fafa;
|
||||||
|
}
|
||||||
|
.plan-card.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.plan-card .pname {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1e4a4f;
|
||||||
|
}
|
||||||
|
.plan-card .pdesc {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
.plan-card .pprice {
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1e4a4f;
|
||||||
|
}
|
||||||
|
.plan-card .pprice small {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
.plan-card ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 4px 0 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.plan-card li::before {
|
||||||
|
content: "✓";
|
||||||
|
color: #2f7f84;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.plan-card .tag {
|
||||||
|
position: absolute;
|
||||||
|
top: -11px;
|
||||||
|
right: 16px;
|
||||||
|
background: #f8efe4;
|
||||||
|
color: #7a5a2e;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 800;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.pay-opts {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.pay-opt {
|
||||||
|
border: 2px solid #e2e4e9;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.pay-opt input {
|
||||||
|
margin-top: 4px;
|
||||||
|
accent-color: #2f7f84;
|
||||||
|
}
|
||||||
|
.pay-opt.sel {
|
||||||
|
border-color: #2f7f84;
|
||||||
|
background: #f4fafa;
|
||||||
|
}
|
||||||
|
.pay-opt b {
|
||||||
|
display: block;
|
||||||
|
color: #1e4a4f;
|
||||||
|
}
|
||||||
|
.pay-opt span {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.total-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background: #f4fafa;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
.total-box .t {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1e4a4f;
|
||||||
|
}
|
||||||
|
.total-box .d {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
.bank-box {
|
||||||
|
border: 1px dashed #b9d7d9;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
@@ -0,0 +1,904 @@
|
|||||||
|
/* =====================================================================
|
||||||
|
YogiBook - stili comuni delle dashboard (scuola, allievo, superadmin)
|
||||||
|
|
||||||
|
Palette dal logo YogiBook:
|
||||||
|
acqua #DBF6F9 · teal #6FBABE · crema #F8EFE4 · sabbia #E2CEB1
|
||||||
|
Il colore d'azione segue il tema della scuola (--bs-primary);
|
||||||
|
se la scuola non ne ha uno, si usa il teal profondo di YogiBook.
|
||||||
|
|
||||||
|
Motivo grafico: i dischi sovrapposti del logo. Ogni pannello ha sotto
|
||||||
|
un "secondo strato" colorato (ombra piena spostata in basso) e il titolo
|
||||||
|
è preceduto da un piccolo disco dello stesso colore.
|
||||||
|
===================================================================== */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--yb-aqua: #dbf6f9;
|
||||||
|
--yb-aqua-soft: #eefafb;
|
||||||
|
--yb-teal: #6fbabe;
|
||||||
|
--yb-teal-deep: #2f7f84;
|
||||||
|
--yb-teal-ink: #1e4a4f;
|
||||||
|
--yb-cream: #f8efe4;
|
||||||
|
--yb-sand: #e2ceb1;
|
||||||
|
--yb-sand-ink: #6b4f2a;
|
||||||
|
|
||||||
|
/* Teal YogiBook; include/dashboard_accent.php lo sostituisce con il colore
|
||||||
|
della scuola solo se è abbastanza scuro per il testo bianco */
|
||||||
|
--db-accent: var(--yb-teal-deep);
|
||||||
|
--db-ink: #1f3437;
|
||||||
|
--db-soft: #5e6e70;
|
||||||
|
--db-line: #e6eeef;
|
||||||
|
--db-warn: #a0620a;
|
||||||
|
--db-alert: #b8382b;
|
||||||
|
--db-ok: #1f7a55;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Sfondo pagina delle dashboard: acqua chiarissimo, fa risaltare i pannelli bianchi */
|
||||||
|
body.yb-dash,
|
||||||
|
body.yb-dash .page-content {
|
||||||
|
background-color: #f4fafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Toni dei pannelli (fill = strato/disco, ink = testo sul tono) */
|
||||||
|
.tone-teal {
|
||||||
|
--tone: var(--yb-teal);
|
||||||
|
--tone-soft: var(--yb-aqua-soft);
|
||||||
|
--tone-ink: var(--yb-teal-deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-aqua {
|
||||||
|
--tone: var(--yb-aqua);
|
||||||
|
--tone-soft: var(--yb-aqua-soft);
|
||||||
|
--tone-ink: var(--yb-teal-deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-cream {
|
||||||
|
--tone: var(--yb-cream);
|
||||||
|
--tone-soft: #fcf8f2;
|
||||||
|
--tone-ink: var(--yb-sand-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-sand {
|
||||||
|
--tone: var(--yb-sand);
|
||||||
|
--tone-soft: #fbf5ec;
|
||||||
|
--tone-ink: var(--yb-sand-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-rose {
|
||||||
|
--tone: #f2c9c0;
|
||||||
|
--tone-soft: #fdf3f1;
|
||||||
|
--tone-ink: #9a3b2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Testata */
|
||||||
|
.db-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px 24px;
|
||||||
|
margin: 4px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-date {
|
||||||
|
font-size: clamp(28px, 4vw, 40px);
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
color: var(--db-ink);
|
||||||
|
line-height: 1.05;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-sub {
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-size: 15px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-sub strong {
|
||||||
|
color: var(--db-ink);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Pannelli: bianco con il "secondo disco" colorato sotto */
|
||||||
|
.db-panel {
|
||||||
|
--tone: var(--yb-aqua);
|
||||||
|
--tone-ink: var(--yb-teal-deep);
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid var(--db-line);
|
||||||
|
box-shadow: 0 6px 0 0 var(--tone);
|
||||||
|
padding: 20px 22px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-panel h2 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-ink);
|
||||||
|
margin: 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-panel h2::before {
|
||||||
|
content: "";
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--tone);
|
||||||
|
box-shadow: 0 3px 0 0 color-mix(in srgb, var(--tone) 55%, var(--tone-ink));
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-panel .db-hint {
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0 0 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-panel-head {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-panel-head a {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tone-ink);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-empty {
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Fascia di numeri: ogni numero su un tono della palette */
|
||||||
|
.db-figures {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure {
|
||||||
|
background: var(--tone-soft, var(--yb-aqua-soft));
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
box-shadow: 0 5px 0 0 var(--tone, var(--yb-aqua));
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure:nth-child(4n + 1) {
|
||||||
|
--tone: var(--yb-teal);
|
||||||
|
--tone-soft: var(--yb-aqua);
|
||||||
|
--tone-ink: var(--yb-teal-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure:nth-child(4n + 2) {
|
||||||
|
--tone: var(--yb-sand);
|
||||||
|
--tone-soft: var(--yb-cream);
|
||||||
|
--tone-ink: var(--yb-sand-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure:nth-child(4n + 3) {
|
||||||
|
--tone: #a9d9dc;
|
||||||
|
--tone-soft: var(--yb-aqua-soft);
|
||||||
|
--tone-ink: var(--yb-teal-deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure:nth-child(4n + 4) {
|
||||||
|
--tone: #d9bc93;
|
||||||
|
--tone-soft: #fbf5ec;
|
||||||
|
--tone-ink: var(--yb-sand-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure-n {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tone-ink, var(--db-ink));
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-figure-l {
|
||||||
|
color: var(--db-ink);
|
||||||
|
opacity: 0.75;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Binario orario con riempimento (classi di oggi) */
|
||||||
|
.db-rail {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-slot {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 66px 1fr;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-top: 1px solid var(--db-line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-slot:first-child {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-slot.is-past {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-time {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--yb-teal-ink);
|
||||||
|
background: var(--yb-aqua);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-next-tag {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--db-accent);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-class {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-swatch {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-teacher {
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-fill {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px 10px;
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--db-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-bar {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 80px;
|
||||||
|
max-width: 280px;
|
||||||
|
height: 9px;
|
||||||
|
border-radius: 9px;
|
||||||
|
background: var(--yb-cream);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-bar span {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 9px;
|
||||||
|
background: linear-gradient(90deg, var(--yb-teal), var(--db-accent));
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-bar.is-full span {
|
||||||
|
background: var(--db-alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-count {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-ink);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-flag {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-flag.warn {
|
||||||
|
color: var(--db-warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-dayoff {
|
||||||
|
background: var(--yb-cream);
|
||||||
|
color: var(--yb-sand-ink);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Da fare: ogni voce con il suo disco colorato */
|
||||||
|
.db-todo {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li + li {
|
||||||
|
border-top: 1px solid var(--db-line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 10px 2px;
|
||||||
|
color: var(--db-ink);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo a:hover .db-todo-text,
|
||||||
|
.db-todo a:focus-visible .db-todo-text {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo-n {
|
||||||
|
flex: 0 0 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
background: var(--item, var(--yb-aqua));
|
||||||
|
color: var(--item-ink, var(--yb-teal-ink));
|
||||||
|
box-shadow: 0 3px 0 0 var(--item-layer, var(--yb-teal));
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li:nth-child(1) {
|
||||||
|
--item: #fce6c8;
|
||||||
|
--item-ink: #8a5208;
|
||||||
|
--item-layer: #ebc48e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li:nth-child(2) {
|
||||||
|
--item: var(--yb-aqua);
|
||||||
|
--item-ink: var(--yb-teal-ink);
|
||||||
|
--item-layer: var(--yb-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li:nth-child(3) {
|
||||||
|
--item: var(--yb-cream);
|
||||||
|
--item-ink: var(--yb-sand-ink);
|
||||||
|
--item-layer: var(--yb-sand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li:nth-child(4) {
|
||||||
|
--item: #fbe1dc;
|
||||||
|
--item-ink: #9a3b2e;
|
||||||
|
--item-layer: #edb3a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li.is-zero .db-todo-n {
|
||||||
|
background: #f1f4f4;
|
||||||
|
color: #9aa6a8;
|
||||||
|
box-shadow: 0 3px 0 0 #e1e7e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-todo li.is-zero .db-todo-text {
|
||||||
|
color: var(--db-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-allclear {
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Tabelle compatte */
|
||||||
|
.db-table {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table th {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-soft);
|
||||||
|
padding: 0 6px 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table td {
|
||||||
|
padding: 9px 6px;
|
||||||
|
border-top: 1px solid var(--db-line);
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table tbody tr:first-child td {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table thead + tbody tr:first-child td {
|
||||||
|
border-top: 1px solid var(--db-line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table .db-muted {
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table .db-right {
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table .db-center {
|
||||||
|
text-align: center;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 2px 9px;
|
||||||
|
white-space: nowrap;
|
||||||
|
background: #eef2f2;
|
||||||
|
color: #4b5a5c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-badge.alert {
|
||||||
|
background: #fbe1dc;
|
||||||
|
color: var(--db-alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-badge.warn {
|
||||||
|
background: #fcebd2;
|
||||||
|
color: var(--db-warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-badge.ok {
|
||||||
|
background: #ddf2e8;
|
||||||
|
color: var(--db-ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-badge.info {
|
||||||
|
background: var(--yb-aqua);
|
||||||
|
color: var(--yb-teal-deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn {
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid var(--db-line);
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 9px;
|
||||||
|
padding: 5px 11px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-ink);
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn:hover {
|
||||||
|
background: var(--yb-aqua-soft);
|
||||||
|
color: var(--db-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn.accept {
|
||||||
|
border-color: #b5e0cc;
|
||||||
|
color: var(--db-ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn.reject {
|
||||||
|
border-color: #f0c2ba;
|
||||||
|
color: var(--db-alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn.primary {
|
||||||
|
background: var(--db-accent);
|
||||||
|
border-color: var(--db-accent);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn.primary:hover {
|
||||||
|
filter: brightness(0.94);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-btn:focus-visible,
|
||||||
|
.db-todo a:focus-visible,
|
||||||
|
.db-panel-head a:focus-visible,
|
||||||
|
.db-school a:focus-visible {
|
||||||
|
outline: 2px solid var(--db-accent);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Allievo: la prossima lezione, con i dischi del logo sullo sfondo */
|
||||||
|
.db-hero {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
isolation: isolate;
|
||||||
|
background: var(--db-accent);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 26px 28px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
box-shadow: 0 7px 0 0 var(--yb-sand);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 6px 26px;
|
||||||
|
align-items: center;
|
||||||
|
min-height: calc(100% - 30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero::before,
|
||||||
|
.db-hero::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero::before {
|
||||||
|
width: 280px;
|
||||||
|
height: 280px;
|
||||||
|
right: -60px;
|
||||||
|
bottom: -150px;
|
||||||
|
background: rgba(248, 239, 228, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero::after {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
right: 30px;
|
||||||
|
bottom: -150px;
|
||||||
|
background: rgba(226, 206, 177, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-when {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.92;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-time {
|
||||||
|
font-size: clamp(46px, 7vw, 66px);
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
line-height: 1;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-class {
|
||||||
|
font-size: 21px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-meta {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.92;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-actions {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
margin-top: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-actions a {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 9px;
|
||||||
|
padding: 7px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero-actions a:hover,
|
||||||
|
.db-hero-actions a:focus-visible {
|
||||||
|
background: rgba(255, 255, 255, 0.32);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero.is-empty {
|
||||||
|
background: var(--yb-cream);
|
||||||
|
color: var(--db-ink);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero.is-empty::before {
|
||||||
|
background: rgba(111, 186, 190, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero.is-empty::after {
|
||||||
|
background: rgba(226, 206, 177, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero.is-empty .db-hero-meta {
|
||||||
|
color: var(--db-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-hero.is-empty .db-hero-actions a {
|
||||||
|
background: var(--db-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
.db-hero {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Allievo: la scuola in cui si trova (logo, indirizzo, mappa, contatti) */
|
||||||
|
.db-school {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid var(--db-line);
|
||||||
|
border-radius: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
box-shadow: 0 7px 0 0 var(--yb-teal);
|
||||||
|
min-height: calc(100% - 30px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-cover {
|
||||||
|
height: 92px;
|
||||||
|
background: var(--yb-aqua) center / cover no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-body {
|
||||||
|
padding: 18px 20px 20px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-id {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-cover + .db-school-body .db-school-id {
|
||||||
|
margin-top: -48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-logo {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
border: 3px solid #fff;
|
||||||
|
box-shadow: 0 3px 0 0 var(--yb-sand);
|
||||||
|
object-fit: contain;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-initials {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--yb-cream);
|
||||||
|
color: var(--yb-sand-ink);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-name {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-ink);
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--db-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-cover + .db-school-body .db-school-name {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-addr {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--db-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-addr i {
|
||||||
|
color: var(--yb-teal-deep);
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-contacts {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-contacts a {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--yb-aqua-soft);
|
||||||
|
color: var(--yb-teal-deep);
|
||||||
|
font-size: 18px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-contacts a:hover {
|
||||||
|
background: var(--yb-aqua);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school details {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--db-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--db-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-school-actions {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Allievo: settimane di pratica */
|
||||||
|
.db-strip {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(16, 1fr);
|
||||||
|
gap: 5px;
|
||||||
|
margin: 6px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-week {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--yb-cream);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-week.l1 {
|
||||||
|
background: color-mix(in srgb, var(--yb-teal) 45%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-week.l2 {
|
||||||
|
background: var(--yb-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-week.l3 {
|
||||||
|
background: var(--db-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-week.is-now {
|
||||||
|
outline: 2px solid var(--yb-sand);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-strip-legend {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: var(--db-soft);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-streak {
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--db-ink);
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-streak strong {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--yb-teal-deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Allievo: pacchetti */
|
||||||
|
.db-pack + .db-pack {
|
||||||
|
border-top: 1px solid var(--db-line);
|
||||||
|
margin-top: 12px;
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-pack-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-pack-top strong {
|
||||||
|
color: var(--db-ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-pack .db-bar {
|
||||||
|
max-width: none;
|
||||||
|
margin: 8px 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-notice {
|
||||||
|
background: var(--yb-cream);
|
||||||
|
border-left: 5px solid var(--yb-sand);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--db-ink);
|
||||||
|
margin-bottom: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Superadmin: grafico e barre */
|
||||||
|
.db-chart {
|
||||||
|
position: relative;
|
||||||
|
height: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-mini-bar {
|
||||||
|
display: inline-block;
|
||||||
|
width: 70px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 7px;
|
||||||
|
background: var(--yb-cream);
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-mini-bar span {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--yb-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
.db-panel {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.db-table .db-hide-sm {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
* {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/* Conferma (SweetAlert2) per i form con class="confirm-form" e data-msg="..." */
|
||||||
|
document.addEventListener("submit", function (ev) {
|
||||||
|
var form = ev.target;
|
||||||
|
if (
|
||||||
|
!form.classList ||
|
||||||
|
!form.classList.contains("confirm-form") ||
|
||||||
|
form.dataset.confirmed === "1"
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
ev.preventDefault();
|
||||||
|
var go = function () {
|
||||||
|
form.dataset.confirmed = "1";
|
||||||
|
form.submit();
|
||||||
|
};
|
||||||
|
if (typeof Swal === "undefined") {
|
||||||
|
if (window.confirm(form.dataset.msg || "Confermi?")) go();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Swal.fire({
|
||||||
|
title: form.dataset.msg || "Confermi?",
|
||||||
|
text: form.dataset.text || "",
|
||||||
|
icon: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: form.dataset.ok || "Conferma",
|
||||||
|
cancelButtonText: "Annulla",
|
||||||
|
confirmButtonColor: form.dataset.color || "#2F7F84",
|
||||||
|
reverseButtons: true,
|
||||||
|
}).then(function (r) {
|
||||||
|
if (r.isConfirmed) go();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,8 +2,11 @@
|
|||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associazione di classi a una classe principale.
|
* Associazione di classi a una classe principale (stessa scuola).
|
||||||
|
* Le classi associate condividono i pacchetti: chi ha un pacchetto della
|
||||||
|
* principale può prenotare anche le associate.
|
||||||
*/
|
*/
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
function e($value): string
|
function e($value): string
|
||||||
@@ -11,101 +14,90 @@ function e($value): string
|
|||||||
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Determina la classe principale (da GET id o POST idservice) ---
|
$idmain = (int) ($_POST['idmainservice'] ?? $_GET['id'] ?? 0);
|
||||||
$idmain = 0;
|
|
||||||
if (isset($_GET['id'])) {
|
// La classe principale deve appartenere alla scuola
|
||||||
$idmain = (int) $_GET['id'];
|
$stmtMain = $pdo->prepare(
|
||||||
}
|
"SELECT service.*, servicecategory.namecategory
|
||||||
if (isset($_POST['idservice'])) {
|
FROM service
|
||||||
$idmain = (int) $_POST['idservice'];
|
LEFT JOIN servicecategory ON service.category = servicecategory.idservicecategory
|
||||||
}
|
WHERE service.idservice = ? AND service.idschool = ?
|
||||||
if (isset($_POST['idmainservice'])) {
|
LIMIT 1"
|
||||||
$idmain = (int) $_POST['idmainservice'];
|
);
|
||||||
|
$stmtMain->execute([$idmain, $idschool]);
|
||||||
|
$mainService = $stmtMain->fetch();
|
||||||
|
if (!$mainService) {
|
||||||
|
header('Location: admin-services.php?message=notfound');
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$insertFeedback = null;
|
$insertFeedback = null;
|
||||||
|
if (isset($_GET['removed'])) {
|
||||||
|
$insertFeedback = ['type' => 'success', 'text' => 'Associazione rimossa.'];
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* Inserimento associazione (POST)
|
* Inserimento associazione (POST)
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
if (isset($_POST['formclass']) && $_POST['formclass'] === 'Y') {
|
if (($_POST['formclass'] ?? '') === 'Y') {
|
||||||
$idmainservice = (int) ($_POST['idmainservice'] ?? 0);
|
$idassoc = (int) ($_POST['servicelist'] ?? 0);
|
||||||
$idassociateservice = (int) ($_POST['servicelist'] ?? 0);
|
|
||||||
|
|
||||||
if ($idmainservice > 0 && $idassociateservice > 0) {
|
if ($idassoc <= 0 || $idassoc === $idmain || !SchoolScope::belongs('service', $idassoc)) {
|
||||||
// Evita duplicati: inserisci solo se l'associazione non esiste già
|
$insertFeedback = ['type' => 'error', 'text' => 'Seleziona una classe valida da associare.'];
|
||||||
$stmtCheck = $pdo->prepare(
|
} else {
|
||||||
|
$chk = $pdo->prepare(
|
||||||
"SELECT COUNT(*) FROM associateclass
|
"SELECT COUNT(*) FROM associateclass
|
||||||
WHERE idmainservice = :main AND idassociateservice = :assoc"
|
WHERE idschool = ? AND idmainservice = ? AND idassociateservice = ?"
|
||||||
);
|
);
|
||||||
$stmtCheck->execute([':main' => $idmainservice, ':assoc' => $idassociateservice]);
|
$chk->execute([$idschool, $idmain, $idassoc]);
|
||||||
$alreadyExists = (int) $stmtCheck->fetchColumn() > 0;
|
if ((int) $chk->fetchColumn() > 0) {
|
||||||
|
|
||||||
if ($alreadyExists) {
|
|
||||||
$insertFeedback = ['type' => 'error', 'text' => 'Questa classe è già associata.'];
|
$insertFeedback = ['type' => 'error', 'text' => 'Questa classe è già associata.'];
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare(
|
$pdo->prepare(
|
||||||
"INSERT INTO associateclass (idmainservice, idassociateservice)
|
"INSERT INTO associateclass (idschool, idmainservice, idassociateservice) VALUES (?, ?, ?)"
|
||||||
VALUES (:main, :assoc)"
|
)->execute([$idschool, $idmain, $idassoc]);
|
||||||
);
|
$insertFeedback = ['type' => 'success', 'text' => 'Associazione aggiunta con successo.'];
|
||||||
$ok = $stmt->execute([
|
|
||||||
':main' => $idmainservice,
|
|
||||||
':assoc' => $idassociateservice,
|
|
||||||
]);
|
|
||||||
$insertFeedback = $ok
|
|
||||||
? ['type' => 'success', 'text' => 'Associazione aggiunta con successo.']
|
|
||||||
: ['type' => 'error', 'text' => 'Errore durante l\'associazione. Riprova.'];
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$insertFeedback = ['type' => 'error', 'text' => 'Seleziona una classe da associare.'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* Dati della classe principale
|
* Classi selezionabili: della scuola, esclusa la principale e le già associate
|
||||||
* ---------------------------------------------------------------------- */
|
|
||||||
$mainService = null;
|
|
||||||
if ($idmain > 0) {
|
|
||||||
$stmtMain = $pdo->prepare(
|
|
||||||
"SELECT service.*, servicecategory.namecategory
|
|
||||||
FROM service
|
|
||||||
LEFT JOIN servicecategory ON service.category = servicecategory.idservicecategory
|
|
||||||
WHERE service.idservice = :idmain
|
|
||||||
LIMIT 1"
|
|
||||||
);
|
|
||||||
$stmtMain->execute([':idmain' => $idmain]);
|
|
||||||
$mainService = $stmtMain->fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
|
||||||
* Elenco delle classi per il dropdown:
|
|
||||||
* esclude la principale E quelle già associate a questa principale.
|
|
||||||
* ---------------------------------------------------------------------- */
|
* ---------------------------------------------------------------------- */
|
||||||
$stmtAll = $pdo->prepare(
|
$stmtAll = $pdo->prepare(
|
||||||
"SELECT idservice, servicename
|
"SELECT idservice, servicename, day, time
|
||||||
FROM service
|
FROM service
|
||||||
WHERE idservice != :idmain
|
WHERE idschool = :idschool
|
||||||
AND idservice NOT IN (
|
AND idservice != :idmain
|
||||||
SELECT idassociateservice
|
AND idservice NOT IN (
|
||||||
FROM associateclass
|
SELECT idassociateservice FROM associateclass
|
||||||
WHERE idmainservice = :idmain2
|
WHERE idschool = :idschool2 AND idmainservice = :idmain2
|
||||||
)
|
)
|
||||||
ORDER BY servicename"
|
ORDER BY servicename"
|
||||||
);
|
);
|
||||||
$stmtAll->execute([':idmain' => $idmain, ':idmain2' => $idmain]);
|
$stmtAll->execute([':idschool' => $idschool, ':idmain' => $idmain, ':idschool2' => $idschool, ':idmain2' => $idmain]);
|
||||||
$allServices = $stmtAll->fetchAll();
|
$allServices = $stmtAll->fetchAll();
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
|
||||||
* Classi già associate alla principale
|
|
||||||
* ---------------------------------------------------------------------- */
|
|
||||||
$stmtAssoc = $pdo->prepare(
|
$stmtAssoc = $pdo->prepare(
|
||||||
"SELECT associateclass.idassociateclass, service.servicename
|
"SELECT associateclass.idassociateclass, service.servicename, service.day, service.time
|
||||||
FROM associateclass
|
FROM associateclass
|
||||||
LEFT JOIN service ON service.idservice = associateclass.idassociateservice
|
LEFT JOIN service ON service.idservice = associateclass.idassociateservice
|
||||||
WHERE associateclass.idmainservice = :idmain"
|
WHERE associateclass.idschool = ? AND associateclass.idmainservice = ?
|
||||||
|
ORDER BY service.servicename"
|
||||||
);
|
);
|
||||||
$stmtAssoc->execute([':idmain' => $idmain]);
|
$stmtAssoc->execute([$idschool, $idmain]);
|
||||||
$associatedClasses = $stmtAssoc->fetchAll();
|
$associatedClasses = $stmtAssoc->fetchAll();
|
||||||
|
|
||||||
|
$dayLabels = [
|
||||||
|
'Monday' => 'Lun',
|
||||||
|
'Tuesday' => 'Mar',
|
||||||
|
'Wednesday' => 'Mer',
|
||||||
|
'Thursday' => 'Gio',
|
||||||
|
'Friday' => 'Ven',
|
||||||
|
'Saturday' => 'Sab',
|
||||||
|
'Sunday' => 'Dom',
|
||||||
|
];
|
||||||
|
$svcLabel = fn($r) => trim($r['servicename'] . ' · ' . ($dayLabels[$r['day']] ?? $r['day']) . ' ' . $r['time']);
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="it">
|
<html lang="it">
|
||||||
@@ -114,17 +106,13 @@ $associatedClasses = $stmtAssoc->fetchAll();
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>YogiBook - Associazione Servizi</title>
|
<title>YogiBook - Associazione Servizi</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta content="YogiBook - Prenotazione facile YogaSoul" name="description" />
|
|
||||||
<meta content="Advanced Creative Solutions" name="author" />
|
|
||||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||||
|
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" /><?php include('include/schooltheme.php'); ?>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
<style>
|
<style>
|
||||||
.admin-card {
|
.admin-card {
|
||||||
border: none;
|
border: none;
|
||||||
@@ -154,7 +142,7 @@ $associatedClasses = $stmtAssoc->fetchAll();
|
|||||||
.main-service-name {
|
.main-service-name {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #1ebf73;
|
color: var(--os-primary, #1ebf73);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-label {
|
.form-label {
|
||||||
@@ -169,11 +157,6 @@ $associatedClasses = $stmtAssoc->fetchAll();
|
|||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-select:focus {
|
|
||||||
border-color: #1ebf73;
|
|
||||||
box-shadow: 0 0 0 3px rgba(30, 191, 115, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-save {
|
.btn-save {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 10px 26px;
|
padding: 10px 26px;
|
||||||
@@ -221,119 +204,86 @@ $associatedClasses = $stmtAssoc->fetchAll();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<?php include('include/languageselection.php'); ?>
|
<?php include('include/schoolswitcher.php'); ?><?php include('include/languageselection.php'); ?>
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
<?php include('include/profiletopbar.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<?php include('include/sidebar.php'); ?>
|
<?php include('include/sidebar.php'); ?>
|
||||||
<header class="ishorizontal-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex"></div>
|
|
||||||
</div>
|
|
||||||
<div class="topnav">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<nav class="navbar navbar-light navbar-expand-lg topnav-menu"></nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
|
<a href="admin-services.php" class="d-inline-block mb-3"><i class="fas fa-arrow-left me-1"></i> Torna alle classi</a>
|
||||||
|
|
||||||
<?php if ($insertFeedback) : ?>
|
<?php if ($insertFeedback) : ?>
|
||||||
<div class="alert alert-<?php echo $insertFeedback['type'] === 'success' ? 'success' : 'danger'; ?>" role="alert">
|
<div class="alert alert-<?php echo $insertFeedback['type'] === 'success' ? 'success' : 'danger'; ?>"><?php echo e($insertFeedback['text']); ?></div>
|
||||||
<?php echo e($insertFeedback['text']); ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Form associazione -->
|
<div class="card admin-card mb-4">
|
||||||
<div class="row">
|
<div class="card-body">
|
||||||
<div class="col-12">
|
<div class="section-title">Classe principale</div>
|
||||||
<div class="card admin-card mb-4">
|
<p class="main-service-name mb-3"><?php echo e($svcLabel($mainService)); ?></p>
|
||||||
<div class="card-body">
|
<p class="section-lead">Associa un'altra classe a questa: chi ha un pacchetto di questa classe potrà prenotare anche quelle associate.</p>
|
||||||
<div class="section-title">Classe principale</div>
|
|
||||||
<p class="main-service-name mb-3">
|
|
||||||
<?php echo $mainService ? e($mainService['servicename']) : 'Classe non trovata'; ?>
|
|
||||||
</p>
|
|
||||||
<p class="section-lead">Associa un'altra classe a questa, così condivideranno la programmazione.</p>
|
|
||||||
|
|
||||||
<form method="post" name="insertclass" id="insertclass">
|
<form method="post">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6 mb-3">
|
||||||
<div class="mb-3">
|
<label for="servicelist" class="form-label">Classe da associare</label>
|
||||||
<label for="servicelist" class="form-label">Classe da associare</label>
|
<select id="servicelist" name="servicelist" class="form-select" required>
|
||||||
<select id="servicelist" name="servicelist" class="form-select" required>
|
<option value="">Seleziona...</option>
|
||||||
<option value="">Seleziona...</option>
|
<?php foreach ($allServices as $svc) : ?>
|
||||||
<?php foreach ($allServices as $svc) : ?>
|
<option value="<?php echo (int) $svc['idservice']; ?>"><?php echo e($svcLabel($svc)); ?></option>
|
||||||
<option value="<?php echo (int) $svc['idservice']; ?>">
|
<?php endforeach; ?>
|
||||||
<?php echo e($svc['servicename']); ?>
|
</select>
|
||||||
</option>
|
<?php if (empty($allServices)) : ?>
|
||||||
<?php endforeach; ?>
|
<small class="text-muted">Tutte le classi disponibili sono già state associate.</small>
|
||||||
</select>
|
<?php endif; ?>
|
||||||
<?php if (empty($allServices)) : ?>
|
</div>
|
||||||
<small class="text-muted">Tutte le classi disponibili sono già state associate.</small>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="idmainservice" value="<?php echo (int) $idmain; ?>">
|
|
||||||
<input type="hidden" name="formclass" value="Y">
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary btn-save">Associa classe</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<input type="hidden" name="idmainservice" value="<?php echo $idmain; ?>">
|
||||||
|
<input type="hidden" name="formclass" value="Y">
|
||||||
|
<button type="submit" class="btn btn-primary btn-save">Associa classe</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Elenco associazioni -->
|
<div class="card admin-card">
|
||||||
<div class="row">
|
<div class="card-body">
|
||||||
<div class="col-12">
|
<div class="section-title">Classi associate</div>
|
||||||
<div class="card admin-card">
|
<p class="section-lead">Classi attualmente collegate a questa principale.</p>
|
||||||
<div class="card-body">
|
<div class="table-responsive">
|
||||||
<div class="section-title">Classi associate</div>
|
<table class="table assoc-table align-middle mb-0">
|
||||||
<p class="section-lead">Classi attualmente collegate a questa principale.</p>
|
<thead>
|
||||||
|
<tr>
|
||||||
<div class="table-responsive">
|
<th>Classe associata</th>
|
||||||
<table class="table assoc-table align-middle mb-0">
|
<th class="text-end">Azione</th>
|
||||||
<thead>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($associatedClasses)) : ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div class="empty-state"><i class="fas fa-link-slash"></i>Nessuna classe associata a questa principale.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php foreach ($associatedClasses as $assoc) : ?>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Classe associata</th>
|
<td><?php echo e($svcLabel($assoc)); ?></td>
|
||||||
<th class="text-end">Azione</th>
|
<td class="text-end">
|
||||||
|
<button type="button" class="btn btn-danger btn-sm btn-remove-assoc"
|
||||||
|
data-href="cancelassociate.php?idassociateclass=<?php echo (int) $assoc['idassociateclass']; ?>&id=<?php echo $idmain; ?>"
|
||||||
|
data-name="<?php echo e($assoc['servicename']); ?>">
|
||||||
|
<i class="fas fa-trash"></i> Rimuovi
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
<?php endforeach; ?>
|
||||||
<tbody>
|
<?php endif; ?>
|
||||||
<?php if (empty($associatedClasses)) : ?>
|
</tbody>
|
||||||
<tr>
|
</table>
|
||||||
<td colspan="2">
|
|
||||||
<div class="empty-state">
|
|
||||||
<i class="fas fa-link-slash"></i>
|
|
||||||
Nessuna classe associata a questa principale.
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php else : ?>
|
|
||||||
<?php foreach ($associatedClasses as $assoc) : ?>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<span class="font-size-14"><?php echo e($assoc['servicename']); ?></span>
|
|
||||||
</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<a href="cancelassociate.php?idassociateclass=<?php echo (int) $assoc['idassociateclass']; ?>&id=<?php echo (int) $idmain; ?>">
|
|
||||||
<button type="button" class="btn btn-danger btn-sm">
|
|
||||||
<i class="fas fa-trash"></i> Rimuovi
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -349,6 +299,22 @@ $associatedClasses = $stmtAssoc->fetchAll();
|
|||||||
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
||||||
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
||||||
<script src="assets/js/app.js"></script>
|
<script src="assets/js/app.js"></script>
|
||||||
|
<script>
|
||||||
|
$('.btn-remove-assoc').on('click', function() {
|
||||||
|
const href = $(this).data('href');
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Rimuovere l\'associazione?',
|
||||||
|
html: '<strong>' + $('<div>').text($(this).data('name')).html() + '</strong>',
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#e74c3c',
|
||||||
|
confirmButtonText: 'Sì, rimuovi',
|
||||||
|
cancelButtonText: 'Annulla'
|
||||||
|
}).then(r => {
|
||||||
|
if (r.isConfirmed) window.location.href = href;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,185 +1,106 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
require_once __DIR__ . '/class/mailer.php';
|
require_once('class/SchoolMail.php');
|
||||||
require_once('include/waitinglist.php');
|
|
||||||
|
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
/**
|
||||||
use PHPMailer\PHPMailer\Exception;
|
* Prenotazione di una lezione da parte dell'allievo, usando un suo pacchetto.
|
||||||
|
* GET: idorder, idnewbooking (idserviceschedule).
|
||||||
|
* L'utente è SEMPRE quello loggato: eventuali iduser/idservicenew nell'URL vengono ignorati.
|
||||||
|
* Esito: 'pending' (c'è posto, lo staff conferma) o 'waiting' (lista d'attesa).
|
||||||
|
*/
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
$iduser = (int) $iduserlogin;
|
||||||
|
|
||||||
// Recupera i parametri GET
|
$idorder = (int) ($_GET['idorder'] ?? 0);
|
||||||
$idorder = isset($_GET['idorder']) ? (int) $_GET['idorder'] : 0;
|
$idschedule = (int) ($_GET['idnewbooking'] ?? 0);
|
||||||
$idnewbooking = isset($_GET['idnewbooking']) ? (int) $_GET['idnewbooking'] : 0;
|
|
||||||
$iduser = isset($_GET['iduser']) ? (int) $_GET['iduser'] : 0;
|
|
||||||
$idservicenew = isset($_GET['idservicenew']) ? (int) $_GET['idservicenew'] : 0;
|
|
||||||
|
|
||||||
// Valida i parametri richiesti
|
function backTo(string $query): void
|
||||||
if ($idorder === 0 || $idnewbooking === 0 || $iduser === 0 || $idservicenew === 0) {
|
{
|
||||||
die("Errore: Parametri mancanti.");
|
header('Location: userpanel.php?' . $query);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Riusa la connessione già aperta da bkngstm.php
|
/* -------------------------------------------------------------------------
|
||||||
$conn = $bkngstm;
|
* Validazioni
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
// Recupera dateschedule e servicename
|
$order = BookingRules::order($idorder, $iduser);
|
||||||
$query = "SELECT serviceschedule.dateschedule, service.servicename
|
if (!$order) {
|
||||||
FROM serviceschedule
|
backTo('bookerror=order');
|
||||||
LEFT JOIN service ON service.idservice = ?
|
|
||||||
WHERE serviceschedule.idserviceschedule = ?";
|
|
||||||
$stmt = $conn->prepare($query);
|
|
||||||
$stmt->bind_param("ii", $idservicenew, $idnewbooking);
|
|
||||||
$stmt->execute();
|
|
||||||
$resultnew = $stmt->get_result();
|
|
||||||
|
|
||||||
if ($resultnew->num_rows > 0) {
|
|
||||||
$rownew = $resultnew->fetch_assoc();
|
|
||||||
$newtime = $rownew['dateschedule'];
|
|
||||||
$servicename = $rownew['servicename'] ?? 'N/D';
|
|
||||||
} else {
|
|
||||||
$stmt->close();
|
|
||||||
die("Errore: Nessun orario trovato per idserviceschedule = $idnewbooking.");
|
|
||||||
}
|
}
|
||||||
$stmt->close();
|
if (BookingRules::isExpired($order)) {
|
||||||
|
backTo('bookerror=expired');
|
||||||
// Formatta la data per l'email
|
|
||||||
$newtimeformat = date("d-m-Y H:i", strtotime($newtime));
|
|
||||||
|
|
||||||
// Recupera nome ed email dell'utente per la mail
|
|
||||||
$firstname = '';
|
|
||||||
$emailuser = '';
|
|
||||||
$stmtUser = $conn->prepare("SELECT first_name, email FROM auth_users WHERE id = ?");
|
|
||||||
$stmtUser->bind_param("i", $iduser);
|
|
||||||
$stmtUser->execute();
|
|
||||||
$resUser = $stmtUser->get_result();
|
|
||||||
if ($rowUser = $resUser->fetch_assoc()) {
|
|
||||||
$firstname = $rowUser['first_name'] ?? '';
|
|
||||||
$emailuser = $rowUser['email'] ?? '';
|
|
||||||
}
|
}
|
||||||
$stmtUser->close();
|
if (BookingRules::remaining($order) <= 0) {
|
||||||
|
backTo('bookerror=notickets');
|
||||||
// Decide lo stato: pending se c'è posto, waiting se la classe è piena
|
|
||||||
$bookingStatus = decideBookingStatus($conn, $idnewbooking);
|
|
||||||
|
|
||||||
if ($bookingStatus === 'full') {
|
|
||||||
// Classe piena e lista d'attesa disattivata: non inseriamo nulla
|
|
||||||
header("Location: userpanel.php?full=Y");
|
|
||||||
exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserisce la nuova prenotazione in bookingclass
|
$schedule = BookingRules::schedule($idschedule);
|
||||||
$insertQuery = "INSERT INTO bookingclass (idserviceschedule, iduser, prevbookingstart, idprevserviceschedule, idservice, idorder, bookingstart, status)
|
if (!$schedule || strtotime($schedule['dateschedule']) <= time()) {
|
||||||
VALUES (?, ?, NULL, '0', ?, ?, ?, ?)";
|
backTo('bookerror=class');
|
||||||
$stmt = $conn->prepare($insertQuery);
|
|
||||||
$stmt->bind_param("iiiiss", $idnewbooking, $iduser, $idservicenew, $idorder, $newtime, $bookingStatus);
|
|
||||||
if (!$stmt->execute()) {
|
|
||||||
$stmt->close();
|
|
||||||
die("Errore durante l'inserimento della nuova prenotazione: " . $conn->error);
|
|
||||||
}
|
}
|
||||||
$stmt->close();
|
if (!in_array((int) $schedule['idservice'], BookingRules::allowedServices((int) $order['idservice']), true)) {
|
||||||
|
backTo('bookerror=class');
|
||||||
// Aggiorna una prenotazione cancellata a pending (se esiste)
|
}
|
||||||
$updateQuery = "UPDATE bookingclass
|
if (!empty($order['expireon']) && substr($schedule['dateschedule'], 0, 10) > $order['expireon']) {
|
||||||
SET status = 'pending'
|
backTo('bookerror=afterexpiry');
|
||||||
WHERE iduser = ? AND idorder = ? AND status = 'cancelled'
|
}
|
||||||
LIMIT 1";
|
if (BookingRules::userHasBooking($idschedule, $iduser)) {
|
||||||
$stmt = $conn->prepare($updateQuery);
|
backTo('bookerror=already');
|
||||||
$stmt->bind_param("ii", $iduser, $idorder);
|
|
||||||
$stmt->execute();
|
|
||||||
$stmt->close();
|
|
||||||
|
|
||||||
// Connessione $bkngstm gestita globalmente: non la chiudiamo qui
|
|
||||||
|
|
||||||
// Parametro di ritorno diverso se finito in lista d'attesa
|
|
||||||
$redirectFlag = ($bookingStatus === 'waiting') ? 'waiting=Y' : 'reprogram=Y';
|
|
||||||
|
|
||||||
// Se non abbiamo un'email valida, salta l'invio ma completa comunque il flusso
|
|
||||||
if ($emailuser === '') {
|
|
||||||
header("Location: userpanel.php?$redirectFlag");
|
|
||||||
exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configura il contenuto dell'email
|
/* -------------------------------------------------------------------------
|
||||||
$messageedit = "
|
* Inserimento (transazione + lock sulla lezione per non superare i posti)
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
* ---------------------------------------------------------------------- */
|
||||||
<span style='font-size: 18px; line-height: 34.2px;'>
|
|
||||||
<strong>Ciao $firstname,</strong>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
Hai inviato una richiesta di riprogrammazione della tua lezione per il servizio <strong>$servicename</strong>.
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
Ecco il dettaglio della riprogrammazione: $newtimeformat
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
La tua richiesta è in fase di accettazione! Verrai avvisata/o se la riprogrammazione è stata accettata.
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<br>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
Per vedere e gestire le tue lezioni clicca qui:
|
|
||||||
<a href='https://yogibook.yogasoul.it'>YogiBook</a>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<br>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
Se non ricordi la password o non hai sei mai entrata in Yogibbok, per prima cosa resettare la password cliccando di seguito:
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<br>
|
|
||||||
<a href='https://yogibook.yogasoul.it/password/reset' target='_blank' style='box-sizing: border-box; display: inline-block; text-decoration: none; text-align: center; color: #FFFFFF; background-color: #3AAEE0; border-radius: 4px; width: auto; max-width: 100%; font-size: 14px;'>
|
|
||||||
<span style='display: block; padding: 10px 20px; line-height: 120%;'>Reset Password</span>
|
|
||||||
</a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
Ci vediamo sul tappetino!
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'>
|
|
||||||
<span style='font-size: 16px; line-height: 30.4px;'>
|
|
||||||
Il Team Yogasoul
|
|
||||||
</span>
|
|
||||||
</p>";
|
|
||||||
|
|
||||||
$buttonedit = "<a href='https://yogibook.yogasoul.it/' target='_blank' class='v-button v-font-size' style='box-sizing: border-box; display: inline-block; text-decoration: none; text-align: center; color: #FFFFFF; background-color: #3AAEE0; border-radius: 4px; width: auto; max-width: 100%; font-size: 14px;'>
|
|
||||||
<span style='display: block; padding: 10px 20px; line-height: 120%;'>YogiBook - YogaSoul</span>
|
|
||||||
</a>";
|
|
||||||
|
|
||||||
// Integra $messageedit in $mailmessage1
|
|
||||||
include('mail/emailtemplate2.php');
|
|
||||||
|
|
||||||
// Configura l'email
|
|
||||||
$mail = new PHPMailer(true);
|
|
||||||
try {
|
try {
|
||||||
$mail->isSMTP();
|
$pdo->beginTransaction();
|
||||||
$mail->Host = $_ENV['MAIL_HOST'];
|
$pdo->prepare("SELECT idserviceschedule FROM serviceschedule WHERE idserviceschedule = ? FOR UPDATE")->execute([$idschedule]);
|
||||||
$mail->SMTPAuth = true;
|
|
||||||
$mail->Username = $_ENV['MAIL_USERNAME'];
|
|
||||||
$mail->Password = $_ENV['MAIL_PASSWORD'];
|
|
||||||
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'];
|
|
||||||
$mail->Port = (int) $_ENV['MAIL_PORT'];
|
|
||||||
|
|
||||||
$mail->setFrom($_ENV['MAIL_FROM_ADDRESS'], $_ENV['MAIL_FROM_NAME']);
|
$status = BookingRules::decideStatus($schedule);
|
||||||
$mail->addAddress($emailuser);
|
if ($status === 'full') {
|
||||||
|
$pdo->rollBack();
|
||||||
|
backTo('full=Y');
|
||||||
|
}
|
||||||
|
|
||||||
$mail->Subject = "Proposta di riprogrammazione!";
|
$pdo->prepare(
|
||||||
$mail->Body = $mailmessage1;
|
"INSERT INTO bookingclass
|
||||||
$mail->AltBody = 'Hai inviato una richiesta di riprogrammazione della tua lezione per il servizio ' . $servicename . ' il ' . $newtimeformat . '. La tua richiesta è in fase di accettazione.';
|
(idschool, idserviceschedule, iduser, prevbookingstart, idprevserviceschedule, idservice, idorder, bookingstart, status)
|
||||||
|
VALUES (?, ?, ?, NULL, 0, ?, ?, ?, ?)"
|
||||||
|
)->execute([
|
||||||
|
$idschool,
|
||||||
|
$idschedule,
|
||||||
|
$iduser,
|
||||||
|
(int) $schedule['idservice'],
|
||||||
|
$idorder,
|
||||||
|
$schedule['dateschedule'],
|
||||||
|
$status,
|
||||||
|
]);
|
||||||
|
|
||||||
$mail->send();
|
$pdo->commit();
|
||||||
} catch (Exception $e) {
|
} catch (Throwable $ex) {
|
||||||
// La prenotazione è già salvata: logghiamo l'errore mail ma non blocchiamo l'utente
|
if ($pdo->inTransaction()) {
|
||||||
error_log("Errore invio mail riprogrammazione (iduser $iduser): " . $mail->ErrorInfo);
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
error_log('bookandgo error (user ' . $iduser . '): ' . $ex->getMessage());
|
||||||
|
backTo('bookerror=save');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Esegui il reindirizzamento
|
/* -------------------------------------------------------------------------
|
||||||
header("Location: userpanel.php?$redirectFlag");
|
* Email (se fallisce, la prenotazione resta valida)
|
||||||
exit();
|
* ---------------------------------------------------------------------- */
|
||||||
|
$h = fn($v) => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
|
||||||
|
$when = date('d-m-Y H:i', strtotime($schedule['dateschedule']));
|
||||||
|
|
||||||
|
if ($status === 'waiting') {
|
||||||
|
SchoolMail::toStudent($emailuser, $firstname, 'Sei in lista d\'attesa', [
|
||||||
|
'La lezione <strong>' . $h($schedule['servicename']) . '</strong> del <strong>' . $when . '</strong> è al completo.',
|
||||||
|
'Sei stata/o inserita/o in <strong>lista d\'attesa</strong>: ti avviseremo se si libera un posto.',
|
||||||
|
]);
|
||||||
|
backTo('waiting=Y');
|
||||||
|
}
|
||||||
|
|
||||||
|
SchoolMail::toStudent($emailuser, $firstname, 'Richiesta di prenotazione ricevuta', [
|
||||||
|
'Abbiamo ricevuto la tua richiesta di prenotazione per <strong>' . $h($schedule['servicename']) . '</strong>.',
|
||||||
|
'Data e ora: <strong>' . $when . '</strong>',
|
||||||
|
'La richiesta è in attesa di conferma: ti avviseremo appena sarà confermata.',
|
||||||
|
]);
|
||||||
|
backTo('booked=Y');
|
||||||
|
|||||||
@@ -1,194 +1,136 @@
|
|||||||
<?php require_once('include/headscript.php'); ?>
|
|
||||||
<?php
|
<?php
|
||||||
// optionquery
|
require_once('include/headscript.php');
|
||||||
$optionquery = new WA_MySQLi_RS("optionquery", $bkngstm, 0);
|
|
||||||
$optionquery->setQuery("SELECT * FROM option");
|
|
||||||
$optionquery->execute();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php
|
/**
|
||||||
// array service possible
|
* Riprogrammazione di una lezione prenotata dall'allievo.
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
* GET: id = idbookingclass da spostare, prev_month/next_month = YYYY-MM.
|
||||||
|
* Mostra le lezioni compatibili (servizio dell'ordine + associate) della scuola
|
||||||
|
* corrente, future ed entro la scadenza del pacchetto.
|
||||||
|
*/
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
$iduserlogin = (int) $iduserlogin;
|
||||||
|
|
||||||
// Verifica della connessione
|
function e($value): string
|
||||||
if ($conn->connect_error) {
|
{
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prendi il valore di idservieordered dalla variabile GET o POST
|
$idprev = (int) ($_GET['id'] ?? 0);
|
||||||
if (isset($_GET['id'])) {
|
|
||||||
$idpreviousbooking = $_GET['id'];
|
/* -------------------------------------------------------------------------
|
||||||
}
|
* 1) La prenotazione da spostare: deve essere dell'utente, della scuola e attiva
|
||||||
if (isset($_POST['idorder'])) {
|
* ---------------------------------------------------------------------- */
|
||||||
$idorder = $_POST['idorder'];
|
$st = $pdo->prepare(
|
||||||
}
|
"SELECT bc.idbookingclass, bc.idservice, bc.idorder, bc.idserviceschedule, ss.dateschedule, s.servicename
|
||||||
if (isset($_GET['idserviceordered'])) {
|
FROM bookingclass bc
|
||||||
$idserviceordered = $_GET['idserviceordered'];
|
JOIN serviceschedule ss ON ss.idserviceschedule = bc.idserviceschedule
|
||||||
}
|
LEFT JOIN service s ON s.idservice = bc.idservice
|
||||||
if (isset($_POST['idserviceordered'])) {
|
WHERE bc.idbookingclass = ? AND bc.iduser = ? AND bc.idschool = ? AND bc.status = 'booked'"
|
||||||
$idserviceordered = $_POST['idserviceordered'];
|
);
|
||||||
|
$st->execute([$idprev, $iduserlogin, $idschool]);
|
||||||
|
$booking = $st->fetch();
|
||||||
|
|
||||||
|
$order = ($booking && $booking['idorder']) ? BookingRules::order((int) $booking['idorder'], $iduserlogin) : null;
|
||||||
|
|
||||||
|
$blockReason = null;
|
||||||
|
if (!$booking) {
|
||||||
|
$blockReason = 'Prenotazione non trovata.';
|
||||||
|
} elseif (!$order) {
|
||||||
|
$blockReason = 'Questa lezione è un omaggio e non può essere spostata.';
|
||||||
|
} elseif (!BookingRules::canReprogram($order)) {
|
||||||
|
$blockReason = 'Hai già usato tutte le riprogrammazioni disponibili per questo pacchetto.';
|
||||||
|
} elseif (!BookingRules::canCancel($booking['dateschedule'])) {
|
||||||
|
$blockReason = 'Non è più possibile spostare questa lezione: il termine per la riprogrammazione è scaduto.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recover the expiry date of the order linked to the booking being rescheduled
|
/* -------------------------------------------------------------------------
|
||||||
$expiryQuery = "SELECT ob.expireon
|
* 2) Mese da visualizzare
|
||||||
FROM bookingclass bc
|
* ---------------------------------------------------------------------- */
|
||||||
INNER JOIN orderbook ob ON bc.idorder = ob.idorderbook
|
$monthParam = $_GET['prev_month'] ?? $_GET['next_month'] ?? '';
|
||||||
WHERE bc.idbookingclass = ?";
|
$currentMonthStart = preg_match('/^\d{4}-\d{2}$/', $monthParam) ? $monthParam . '-01' : date('Y-m-01');
|
||||||
|
$currentMonthEnd = date('Y-m-t', strtotime($currentMonthStart));
|
||||||
|
|
||||||
$stmt = $conn->prepare($expiryQuery);
|
/* -------------------------------------------------------------------------
|
||||||
$stmt->bind_param("i", $idpreviousbooking);
|
* 3) Lezioni disponibili (una sola query, con posti occupati e "già prenotata")
|
||||||
$stmt->execute();
|
* ---------------------------------------------------------------------- */
|
||||||
$expiryResult = $stmt->get_result();
|
$classes = [];
|
||||||
|
$expiry = null;
|
||||||
|
|
||||||
$expiryDate = null;
|
if (!$blockReason) {
|
||||||
if ($expiryResult->num_rows > 0) {
|
$allowed = BookingRules::allowedServices((int) ($order['idservice'] ?: $booking['idservice']));
|
||||||
$row = $expiryResult->fetch_assoc();
|
$expiry = $order['expireon'] ?: null;
|
||||||
if (!empty($row['expireon'])) {
|
|
||||||
$expiryDate = new DateTime($row['expireon']);
|
$ph = implode(',', array_fill(0, count($allowed), '?'));
|
||||||
|
$sql = "SELECT ss.idserviceschedule, ss.idservice, ss.dateschedule,
|
||||||
|
s.servicename, s.maxcapacity, s.colorclass,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b
|
||||||
|
WHERE b.idserviceschedule = ss.idserviceschedule AND b.status IN ('booked','pending')) AS occupied,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b2
|
||||||
|
WHERE b2.idserviceschedule = ss.idserviceschedule AND b2.iduser = ? AND b2.status <> 'cancelled') AS mine
|
||||||
|
FROM serviceschedule ss
|
||||||
|
JOIN service s ON s.idservice = ss.idservice
|
||||||
|
WHERE ss.idschool = ?
|
||||||
|
AND ss.idservice IN ($ph)
|
||||||
|
AND ss.idserviceschedule <> ?
|
||||||
|
AND ss.dateschedule > NOW()
|
||||||
|
AND ss.dateschedule BETWEEN ? AND DATE_ADD(?, INTERVAL 1 DAY)"
|
||||||
|
. ($expiry ? " AND ss.dateschedule <= ?" : "") . "
|
||||||
|
ORDER BY ss.dateschedule";
|
||||||
|
|
||||||
|
$params = array_merge([$iduserlogin, $idschool], $allowed, [(int) $booking['idserviceschedule'], $currentMonthStart, $currentMonthEnd]);
|
||||||
|
if ($expiry) {
|
||||||
|
$params[] = $expiry . ' 23:59:59';
|
||||||
}
|
}
|
||||||
|
$st = $pdo->prepare($sql);
|
||||||
|
$st->execute($params);
|
||||||
|
$classes = $st->fetchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt->close();
|
$waitingEnabled = BookingRules::waitingListEnabled();
|
||||||
|
$schoolAddress = implode(', ', array_filter([
|
||||||
|
trim((string) ($schoolData['address'] ?? '')),
|
||||||
|
trim((string) ($schoolData['city'] ?? '')),
|
||||||
|
]));
|
||||||
|
|
||||||
// Query sulla tabella associateclass
|
$italianMonths = [
|
||||||
$sql = "SELECT idassociateservice FROM associateclass WHERE idmainservice = ?";
|
"January" => "Gennaio",
|
||||||
$stmt = $conn->prepare($sql);
|
"February" => "Febbraio",
|
||||||
$stmt->bind_param("i", $idserviceordered);
|
"March" => "Marzo",
|
||||||
$stmt->execute();
|
"April" => "Aprile",
|
||||||
$result = $stmt->get_result();
|
"May" => "Maggio",
|
||||||
|
"June" => "Giugno",
|
||||||
$idassociateservices = array();
|
"July" => "Luglio",
|
||||||
array_push($idassociateservices, $idserviceordered);
|
"August" => "Agosto",
|
||||||
if ($result->num_rows > 0) {
|
"September" => "Settembre",
|
||||||
while ($row = $result->fetch_assoc()) {
|
"October" => "Ottobre",
|
||||||
$idassociateservices[] = $row['idassociateservice'];
|
"November" => "Novembre",
|
||||||
}
|
"December" => "Dicembre",
|
||||||
}
|
];
|
||||||
|
$monthLabel = $italianMonths[date('F', strtotime($currentMonthStart))] . ' ' . date('Y', strtotime($currentMonthStart));
|
||||||
$stmt->close();
|
$navBase = 'bookingpanel.php?id=' . $idprev;
|
||||||
$conn->close();
|
$prevLink = $navBase . '&prev_month=' . date('Y-m', strtotime('-1 month', strtotime($currentMonthStart)));
|
||||||
|
$nextLink = $navBase . '&next_month=' . date('Y-m', strtotime('+1 month', strtotime($currentMonthStart)));
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php
|
|
||||||
$bookedclass = new WA_MySQLi_RS("bookedclass", $bkngstm, 0);
|
|
||||||
|
|
||||||
// Verifica se è stata specificata una richiesta per cambiare il mese
|
|
||||||
if (isset($_GET['prev_month'])) {
|
|
||||||
$currentMonthStart = $_GET['prev_month'] . '-01';
|
|
||||||
} elseif (isset($_GET['next_month'])) {
|
|
||||||
$currentMonthStart = $_GET['next_month'] . '-01';
|
|
||||||
} else {
|
|
||||||
$currentMonthStart = date("Y-m-01");
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentMonthEnd = date("Y-m-t", strtotime($currentMonthStart));
|
|
||||||
|
|
||||||
// Aggiungi filtro per la data di scadenza se definita, includendo la data di scadenza
|
|
||||||
$expiryCondition = '';
|
|
||||||
if ($expiryDate) {
|
|
||||||
$expiryCondition = "AND (serviceschedule.dateschedule <= '{$expiryDate->format('Y-m-d 23:59:59')}' OR serviceschedule.dateschedule = '{$expiryDate->format('Y-m-d')}')";
|
|
||||||
}
|
|
||||||
|
|
||||||
$bookedclass->setQuery("SELECT * FROM serviceschedule
|
|
||||||
LEFT JOIN service ON serviceschedule.idservice = service.idservice
|
|
||||||
WHERE serviceschedule.dateschedule BETWEEN '$currentMonthStart' AND DATE_ADD('$currentMonthEnd', INTERVAL 1 DAY)
|
|
||||||
$expiryCondition
|
|
||||||
ORDER BY serviceschedule.dateschedule");
|
|
||||||
$bookedclass->execute();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID dell'utente per il quale vuoi filtrare gli ordini
|
|
||||||
$userid = 1;
|
|
||||||
|
|
||||||
// Query per ottenere la somma dei ticket per ogni ordine dell'utente
|
|
||||||
$query = "SELECT iduser, idorderbook, SUM(nticket) as total_tickets
|
|
||||||
FROM orderbook
|
|
||||||
WHERE iduser = $userid
|
|
||||||
GROUP BY iduser";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
die("Query fallita: " . $conn->error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$idOrdine = $row["idorderbook"];
|
|
||||||
$totalTickets = $row["total_tickets"];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$totalTickets = 0; // Imposta a zero se non ci sono righe nella query
|
|
||||||
}
|
|
||||||
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
//check tickets
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
$iduser = 1; // Sostituisci con l'ID utente desiderato
|
|
||||||
$currentDateTime = date("Y-m-d H:i:s");
|
|
||||||
|
|
||||||
$query = "SELECT COUNT(*) AS total,
|
|
||||||
SUM(CASE WHEN serviceschedule.dateschedule <= '$currentDateTime' THEN 1 ELSE 0 END) AS passed,
|
|
||||||
SUM(CASE WHEN serviceschedule.dateschedule > '$currentDateTime' THEN 1 ELSE 0 END) AS future
|
|
||||||
FROM bookingclass
|
|
||||||
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
|
|
||||||
WHERE bookingclass.iduser = $iduser";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
if ($result) {
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
$totalRecords = $row['total'];
|
|
||||||
$passedRecords = $row['passed'];
|
|
||||||
$futureRecords = $row['future'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="it">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>YogiBook - Prenotazioni YogaSoul</title>
|
<title>YogiBook - <?php echo e($schoolname); ?></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta content="YogiBook - Prenotazione facile YogaSOul" name="description" />
|
|
||||||
<meta content="Advanced Creative Solutions" author />
|
|
||||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" /><?php include('include/schooltheme.php'); ?>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.custom-card {
|
.custom-card {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
box-shadow: 0 3px 16px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 3px 16px rgba(0, 0, 0, .06);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
|
||||||
transition: box-shadow 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card:hover {
|
|
||||||
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-date-box {
|
.custom-date-box {
|
||||||
@@ -210,7 +152,7 @@ $conn->close();
|
|||||||
.custom-month {
|
.custom-month {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: .05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-event-details {
|
.custom-event-details {
|
||||||
@@ -220,7 +162,6 @@ $conn->close();
|
|||||||
padding: 18px 22px;
|
padding: 18px 22px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-left: 20px solid #ccc;
|
border-left: 20px solid #ccc;
|
||||||
/* colore impostato inline per ogni card in base allo stato */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-heading {
|
.custom-heading {
|
||||||
@@ -236,32 +177,52 @@ $conn->close();
|
|||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-actions {
|
.booking-button {
|
||||||
display: none;
|
display: inline-block;
|
||||||
flex-direction: row;
|
|
||||||
gap: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card.expanded .custom-actions {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-action-button {
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 7px 14px;
|
padding: 8px 16px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: #eef2f7;
|
background: #eef2f7;
|
||||||
color: #374151;
|
color: #374151;
|
||||||
cursor: pointer;
|
margin-top: 10px;
|
||||||
transition: filter 0.15s;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-action-button:hover {
|
.booking-button.go {
|
||||||
filter: brightness(0.94);
|
background: #1ebf73;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.booking-button.wait {
|
||||||
|
background: #d1698a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-navigation {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
margin: 10px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-navigation h2 {
|
||||||
|
margin: 0;
|
||||||
|
min-width: 220px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.from-box {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 3px 16px rgba(0, 0, 0, .06);
|
||||||
|
padding: 18px 22px;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -280,111 +241,9 @@ $conn->close();
|
|||||||
.custom-day {
|
.custom-day {
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-month {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.month-navigation {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.month-nav-button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-month {
|
|
||||||
font-size: 24px;
|
|
||||||
margin: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color {
|
|
||||||
border: 1px solid #D1C4CC;
|
|
||||||
padding: 0px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 20px;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.blue {
|
|
||||||
background-color: #D4E1F1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.green {
|
|
||||||
background-color: #FFD8B5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.pink {
|
|
||||||
background-color: #C3E6CB;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.purple {
|
|
||||||
background-color: #F4CCCC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.pastel-color {
|
|
||||||
margin-right: 0;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-details {
|
|
||||||
margin-top: 10px;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-table td {
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
background-color: #ff6347;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
padding: 5px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button:hover {
|
|
||||||
background-color: #d64937;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
</head>
|
||||||
<script>
|
|
||||||
function confirmDelete(id, deletePageUrl) {
|
|
||||||
Swal.fire({
|
|
||||||
title: "Sei sicuro?",
|
|
||||||
text: "Questa prenotazione verrà cancellata definitivamente! Ricordati poi di riprogrammare la tua lezione!",
|
|
||||||
icon: "warning",
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonColor: "#d33",
|
|
||||||
cancelButtonColor: "#3085d6",
|
|
||||||
confirmButtonText: "Sì, cancella!",
|
|
||||||
cancelButtonText: "Annulla"
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
window.location.href = `deleteclass.php?id=${id}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="layout-wrapper">
|
<div id="layout-wrapper">
|
||||||
@@ -400,214 +259,99 @@ $conn->close();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<?php include('include/languageselection.php'); ?>
|
<?php include('include/schoolswitcher.php'); ?><?php include('include/languageselection.php'); ?>
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
<?php include('include/profiletopbar.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<?php include('include/sidebar.php'); ?>
|
<?php include('include/sidebar.php'); ?>
|
||||||
<header class="ishorizontal-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex"></div>
|
|
||||||
</div>
|
|
||||||
<div class="topnav">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<nav class="navbar navbar-light navbar-expand-lg topnav-menu"></nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<?php
|
|
||||||
$toprogram = $totalTickets - $passedRecords - $futureRecords;
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<a href="userpanel.php" class="d-inline-block mb-3"><i class="fas fa-arrow-left me-1"></i> Torna alle tue lezioni</a>
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
<?php if ($blockReason) : ?>
|
||||||
<div class="card">
|
<div class="alert alert-warning"><i class="fas fa-circle-info me-1"></i> <?php echo e($blockReason); ?></div>
|
||||||
<div class="card-body">
|
<?php else : ?>
|
||||||
<div class="">
|
|
||||||
<div class="row mb-2">
|
<div class="from-box">
|
||||||
<div class="col-xl-3 col-md-12">
|
<div class="text-muted" style="font-size:13px;">Stai spostando</div>
|
||||||
<div class="pb-3 pb-xl-0">
|
<strong style="font-size:17px;"><?php echo e($booking['servicename']); ?></strong>
|
||||||
<form class="email-search">
|
del <strong><?php echo e(date('d-m-Y H:i', strtotime($booking['dateschedule']))); ?></strong>
|
||||||
<div class="position-relative">
|
<div class="text-muted mt-1" style="font-size:13px;">
|
||||||
<h3>Riprogrammazione Lezione</h3>
|
Riprogrammazioni usate: <?php echo (int) $order['reprogrammed']; ?> su <?php echo (int) $order['maxreschedule']; ?>
|
||||||
</div>
|
<?php if ($expiry) : ?> · Pacchetto valido fino al <?php echo e(date('d-m-Y', strtotime($expiry))); ?><?php endif; ?>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-xl-9 col-md-12">
|
<div class="month-navigation">
|
||||||
<div class="text-sm-end">
|
<a href="<?php echo e($prevLink); ?>"><i class="fas fa-chevron-left fa-2x"></i></a>
|
||||||
<?php if ($toprogram > 0) {
|
<h2><?php echo e($monthLabel); ?></h2>
|
||||||
echo '<button type="button" class="btn btn-info btn-rounded waves-effect waves-light mb-2 me-2" data-bs-toggle="modal" data-bs-target=".create-task"><i class="mdi mdi-plus me-1"></i> Programma Lezioni</button>';
|
<a href="<?php echo e($nextLink); ?>"><i class="fas fa-chevron-right fa-2x"></i></a>
|
||||||
}
|
</div>
|
||||||
?>
|
|
||||||
<button type="button" class="btn btn-success btn-rounded waves-effect waves-light mb-2 me-2" data-bs-toggle="modal" data-bs-target=".create-task"><i class="mdi mdi-plus me-1"></i> Acquista Pacchetto Lezioni</button>
|
<?php if (empty($classes)) : ?>
|
||||||
</div>
|
<p class="text-center text-muted">Nessuna lezione disponibile in questo mese<?php echo $expiry ? ' entro la scadenza del pacchetto' : ''; ?>.</p>
|
||||||
</div>
|
<?php endif; ?>
|
||||||
</div>
|
|
||||||
|
<?php foreach ($classes as $c) :
|
||||||
|
$d = new DateTime($c['dateschedule']);
|
||||||
|
$max = (int) $c['maxcapacity'];
|
||||||
|
$occ = (int) $c['occupied'];
|
||||||
|
$free = $max <= 0 || $occ < $max;
|
||||||
|
$mine = (int) $c['mine'] > 0;
|
||||||
|
$boxColor = $mine ? '#FF6609' : ($free ? '#1ebf73' : '#d1698a');
|
||||||
|
$link = 'rebookandgo.php?idpreviousbooking=' . $idprev
|
||||||
|
. '&idservicenew=' . (int) $c['idservice']
|
||||||
|
. '&idnewbooking=' . (int) $c['idserviceschedule']
|
||||||
|
. '&iduser=' . $iduserlogin;
|
||||||
|
?>
|
||||||
|
<div class="custom-card">
|
||||||
|
<div class="custom-date-box" style="background:<?php echo $boxColor; ?>;">
|
||||||
|
<div class="custom-day"><?php echo $d->format('d'); ?></div>
|
||||||
|
<div class="custom-month"><?php echo e($italianMonths[$d->format('F')]); ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="custom-event-details" style="border-left-color:<?php echo e($mine ? '#FF6609' : ($free ? ($c['colorclass'] ?: '#1ebf73') : '#d1698a')); ?>;">
|
||||||
|
<h2 class="custom-heading"><?php echo e($c['servicename']); ?> · <?php echo $occ; ?>/<?php echo $max; ?></h2>
|
||||||
|
<p class="custom-paragraph">Quando: <?php echo e($d->format('d-m-Y H:i')); ?></p>
|
||||||
|
<?php if ($schoolAddress !== '') : ?><p class="custom-paragraph">Luogo: <?php echo e($schoolAddress); ?></p><?php endif; ?>
|
||||||
|
<div>
|
||||||
|
<?php if ($mine) : ?>
|
||||||
|
<span class="booking-button"><i class="fa fa-check"></i> Sei già prenotata/o</span>
|
||||||
|
<?php elseif ($free) : ?>
|
||||||
|
<a class="booking-button go" href="<?php echo e($link); ?>"><i class="fas fa-arrow-circle-right"></i> Sposta qui</a>
|
||||||
|
<?php elseif ($waitingEnabled) : ?>
|
||||||
|
<a class="booking-button wait" href="<?php echo e($link); ?>"><i class="fas fa-hourglass-half"></i> Mettiti in lista d'attesa</a>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="booking-button"><i class="fa fa-stop"></i> Classe piena</span>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<?php endforeach; ?>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<?php if (!empty($classes)) : ?>
|
||||||
<?php
|
<div class="month-navigation">
|
||||||
$italianMonths = [
|
<a href="<?php echo e($prevLink); ?>"><i class="fas fa-chevron-left fa-2x"></i></a>
|
||||||
"January" => "Gennaio",
|
<h2><?php echo e($monthLabel); ?></h2>
|
||||||
"February" => "Febbraio",
|
<a href="<?php echo e($nextLink); ?>"><i class="fas fa-chevron-right fa-2x"></i></a>
|
||||||
"March" => "Marzo",
|
</div>
|
||||||
"April" => "Aprile",
|
<?php endif; ?>
|
||||||
"May" => "Maggio",
|
<?php endif; ?>
|
||||||
"June" => "Giugno",
|
|
||||||
"July" => "Luglio",
|
|
||||||
"August" => "Agosto",
|
|
||||||
"September" => "Settembre",
|
|
||||||
"October" => "Ottobre",
|
|
||||||
"November" => "Novembre",
|
|
||||||
"December" => "Dicembre"
|
|
||||||
];
|
|
||||||
?>
|
|
||||||
<div class="month-navigation">
|
|
||||||
<a href="?prev_month=<?php echo date('Y-m', strtotime('-1 month', strtotime($currentMonthStart))); ?>&idserviceordered=<?php echo $idserviceordered; ?>&id=<?php echo $idpreviousbooking; ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-left fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
<h2><?php echo $italianMonths[date("F", strtotime($currentMonthStart))] . ' ' . date("Y", strtotime($currentMonthStart)); ?></h2>
|
|
||||||
<a href="?next_month=<?php echo date('Y-m', strtotime('+1 month', strtotime($currentMonthStart))); ?>&idserviceordered=<?php echo $idserviceordered; ?>&id=<?php echo $idpreviousbooking; ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-right fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php
|
</div>
|
||||||
$wa_startindex = 0;
|
<?php include('include/footer.php'); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
if ($bookedclass->TotalRows == 0) {
|
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||||
echo "<p>Classi non presenti per questo mese o oltre la data di scadenza</p>";
|
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
||||||
} else {
|
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
||||||
while (!$bookedclass->atEnd()) {
|
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
||||||
$wa_startindex = $bookedclass->Index;
|
<script src="assets/js/app.js"></script>
|
||||||
$dateschedule = $bookedclass->getColumnVal("dateschedule");
|
|
||||||
$dateObj = new DateTime($dateschedule);
|
|
||||||
$dayInItalian = $dateObj->format("d");
|
|
||||||
$monthInItalian = $italianMonths[$dateObj->format("F")];
|
|
||||||
$newDateFormat = $dateObj->format("d-m-Y H:i");
|
|
||||||
|
|
||||||
$currentTime = new DateTime();
|
|
||||||
$classTime = new DateTime($dateschedule);
|
|
||||||
$timeDifference = $classTime->diff($currentTime);
|
|
||||||
$hoursDifference = $timeDifference->h + $timeDifference->days * 24;
|
|
||||||
$timetocancel = $optionquery->getColumnVal("maxbeforetimecancell");
|
|
||||||
$canBeDeleted = ($hoursDifference >= $timetocancel);
|
|
||||||
|
|
||||||
$mysqli = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
$eventId = $bookedclass->getColumnVal("idserviceschedule");
|
|
||||||
$bookingQuery = "SELECT iduser FROM bookingclass WHERE bookingclass.idserviceschedule = ? AND bookingclass.status IN ('booked','pending')";
|
|
||||||
$stmt = $mysqli->prepare($bookingQuery);
|
|
||||||
$stmt->bind_param("i", $eventId);
|
|
||||||
$stmt->execute();
|
|
||||||
$bookingResult = $stmt->get_result();
|
|
||||||
$countPersons = $bookingResult->num_rows;
|
|
||||||
$stmt->close();
|
|
||||||
|
|
||||||
$cardservice = $bookedclass->getColumnVal("idservice");
|
|
||||||
if (in_array($cardservice, $idassociateservices)) {
|
|
||||||
$maxcapacity = $bookedclass->getColumnVal("maxcapacity");
|
|
||||||
$freeplace = $maxcapacity - $countPersons;
|
|
||||||
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
$idcheckservice = $bookedclass->getColumnVal("idserviceschedule");
|
|
||||||
$iduser = $iduserlog;
|
|
||||||
$query = "SELECT * FROM bookingclass WHERE idserviceschedule = ? AND iduser = ?";
|
|
||||||
$stmt = $conn->prepare($query);
|
|
||||||
$stmt->bind_param("ii", $idcheckservice, $iduser);
|
|
||||||
$stmt->execute();
|
|
||||||
$resultcheck = $stmt->get_result();
|
|
||||||
$alreadybooked = $resultcheck->num_rows > 0 ? 'Y' : 'N';
|
|
||||||
$stmt->close();
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
<div class="custom-card" onclick="toggleCard(this)">
|
|
||||||
<?php if ($alreadybooked == 'Y') { ?>
|
|
||||||
<div class="custom-date-box" style="background-color:#FF6609">
|
|
||||||
<?php } elseif ($freeplace > 0) { ?>
|
|
||||||
<div class="custom-date-box" style="background-color:#1ebf73">
|
|
||||||
<?php } else { ?>
|
|
||||||
<div class="custom-date-box" style="background-color:#d1698a">
|
|
||||||
<?php } ?>
|
|
||||||
<div class="custom-day"><?php echo $dayInItalian; ?></div>
|
|
||||||
<div class="custom-month"><?php echo $monthInItalian; ?></div>
|
|
||||||
</div>
|
|
||||||
<?php if ($alreadybooked == 'Y') { ?>
|
|
||||||
<div class="custom-event-details" style="background-color:#FFAC7A;border-left-color:#FF6609">
|
|
||||||
<?php } elseif ($freeplace > 0) { ?>
|
|
||||||
<div class="custom-event-details" style="border-left-color:<?php echo ($bookedclass->getColumnVal("colorclass")); ?>">
|
|
||||||
<?php } else { ?>
|
|
||||||
<div class="custom-event-details" style="background-color:#fbeef3;border-left-color:#d1698a">
|
|
||||||
<?php } ?>
|
|
||||||
<h2 class="custom-heading"><?php echo ($bookedclass->getColumnVal("servicename")); ?> -<?php echo $countPersons; ?>/<?php echo ($bookedclass->getColumnVal("maxcapacity")); ?></h2>
|
|
||||||
<p class="custom-paragraph">Quando: <?php echo $newDateFormat; ?></p>
|
|
||||||
<p class="custom-paragraph">Luogo: via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
|
||||||
<?php $idnewbooking = $bookedclass->getColumnVal("idserviceschedule"); ?>
|
|
||||||
<?php $idservicenew = $bookedclass->getColumnVal("idservice"); ?>
|
|
||||||
<div class="booking-details">
|
|
||||||
<?php if ($alreadybooked == 'Y') { ?>
|
|
||||||
<button class="booking-button"><i class="fa fa-check"></i> Sei già prenotata/o</button>
|
|
||||||
<?php } elseif ($freeplace > 0) { ?>
|
|
||||||
<a href="rebookandgo.php?idpreviousbooking=<?php echo $idpreviousbooking; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button"><i class="fas fa-arrow-circle-right"></i> Riprogramma Classe</button></a>
|
|
||||||
<?php } else { ?>
|
|
||||||
<?php if ($optionquery->getColumnVal("waitinglist_enabled") === 'Y') { ?>
|
|
||||||
<a href="rebookandgo.php?idpreviousbooking=<?php echo $idpreviousbooking; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button" style="background-color:#d1698a;color:#fff;"><i class="fas fa-hourglass-half"></i> Mettiti in lista d'attesa</button></a>
|
|
||||||
<?php } else { ?>
|
|
||||||
<button class="booking-button"><i class="fa fa-stop"></i> Classe Piena</button>
|
|
||||||
<?php } ?>
|
|
||||||
<?php } ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
$bookedclass->moveNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bookedclass->moveFirst();
|
|
||||||
unset($wa_startindex);
|
|
||||||
unset($wa_repeatcount);
|
|
||||||
?>
|
|
||||||
<div class="month-navigation">
|
|
||||||
<a href="?prev_month=<?php echo date('Y-m', strtotime('-1 month', strtotime($currentMonthStart))); ?>&idserviceordered=<?php echo $idserviceordered; ?>&id=<?php echo $idpreviousbooking; ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-left fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
<h2><?php echo $italianMonths[date("F", strtotime($currentMonthStart))] . ' ' . date("Y", strtotime($currentMonthStart)); ?></h2>
|
|
||||||
<a href="?next_month=<?php echo date('Y-m', strtotime('+1 month', strtotime($currentMonthStart))); ?>&idserviceordered=<?php echo $idserviceordered; ?>&id=<?php echo $idpreviousbooking; ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-right fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleCard(card) {
|
|
||||||
card.classList.toggle("expanded");
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
|
||||||
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
|
||||||
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
|
||||||
<script src="assets/js/app.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,218 +1,116 @@
|
|||||||
<?php require_once('include/headscript.php'); ?>
|
|
||||||
<?php // require_once('Connections/bkngstm.php');
|
|
||||||
?>
|
|
||||||
<?php // require_once('webassist/mysqli/rsobj.php');
|
|
||||||
?>
|
|
||||||
<?php // require_once('webassist/mysqli/queryobj.php');
|
|
||||||
?>
|
|
||||||
<?php // optionquery
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$optionquery = new WA_MySQLi_RS("optionquery", $bkngstm, 0);
|
|
||||||
$optionquery->setQuery("SELECT * FROM option");
|
|
||||||
$optionquery->execute();
|
|
||||||
?>
|
|
||||||
<?php // array servicesordered
|
|
||||||
/* $conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
|
|
||||||
// Verifica della connessione
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID dell'utente per cui eseguire la query
|
|
||||||
$iduser = 1;
|
|
||||||
|
|
||||||
// Query per selezionare i valori della colonna idservice per lo specifico iduser
|
|
||||||
$sql = "SELECT idservice FROM orderbook WHERE iduser = $iduser";
|
|
||||||
$result = $conn->query($sql);
|
|
||||||
|
|
||||||
$idserviceordered = array();
|
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
|
||||||
// Memorizza i valori della colonna idservice nell'array $idserviceordered
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$idserviceordered[] = $row['idservice'];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo "Nessun risultato trovato.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chiudi la connessione al database
|
|
||||||
$conn->close();
|
|
||||||
|
|
||||||
// Esempio di stampa dei valori memorizzati nell'array $idserviceordered
|
|
||||||
print_r($idserviceordered); */
|
|
||||||
?>
|
|
||||||
<?php // array service possible
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
|
|
||||||
// Verifica della connessione
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prendi il valore di idservieordered dalla variabile GET
|
|
||||||
if (isset($_GET['id'])) {
|
|
||||||
$idpreviousbooking = $_GET['id'];
|
|
||||||
}
|
|
||||||
if (isset($_POST['idorder'])) {
|
|
||||||
$idorder = $_POST['idorder'];
|
|
||||||
}
|
|
||||||
if (isset($_GET['idorder'])) {
|
|
||||||
$idorder = $_GET['idorder'];
|
|
||||||
}
|
|
||||||
if (isset($_GET['idserviceordered'])) {
|
|
||||||
$idserviceordered = $_GET['idserviceordered'];
|
|
||||||
}
|
|
||||||
if (isset($_POST['idserviceordered'])) {
|
|
||||||
$idserviceordered = $_POST['idserviceordered'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Query sulla tabella associateclass
|
|
||||||
$sql = "SELECT idassociateservice FROM associateclass WHERE idmainservice = $idserviceordered";
|
|
||||||
$result = $conn->query($sql);
|
|
||||||
|
|
||||||
$idassociateservices = array();
|
|
||||||
array_push($idassociateservices, $idserviceordered);
|
|
||||||
if ($result->num_rows > 0) {
|
|
||||||
// Memorizza i valori della colonna idassociateservice nell'array $idassociateservices
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$idassociateservices[] = $row['idassociateservice'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chiudi la connessione al database
|
|
||||||
$conn->close();
|
|
||||||
|
|
||||||
// Esempio di stampa dei valori memorizzati nell'array $idassociateservices
|
|
||||||
//print_r($idassociateservices);
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$bookedclass = new WA_MySQLi_RS("bookedclass", $bkngstm, 0);
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
// Verifica se è stata specificata una richiesta per cambiare il mese
|
/**
|
||||||
if (isset($_GET['prev_month'])) {
|
* Prenotazione lezioni da un pacchetto (ordine) dell'allievo.
|
||||||
$currentMonthStart = $_GET['prev_month'] . '-01';
|
* POST (da selectorder) o GET (navigazione mesi): idorder; prev_month/next_month = YYYY-MM.
|
||||||
} elseif (isset($_GET['next_month'])) {
|
* Mostra le lezioni compatibili (servizio dell'ordine + associate) della scuola
|
||||||
$currentMonthStart = $_GET['next_month'] . '-01';
|
* corrente, future ed entro la scadenza. La prenotazione avviene in bookandgo.php.
|
||||||
|
*/
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
$iduserlogin = (int) $iduserlogin;
|
||||||
|
|
||||||
|
function e($value): string
|
||||||
|
{
|
||||||
|
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
$idorder = (int) ($_POST['idorder'] ?? $_GET['idorder'] ?? 0);
|
||||||
|
$order = BookingRules::order($idorder, $iduserlogin);
|
||||||
|
|
||||||
|
$blockReason = null;
|
||||||
|
$remaining = 0;
|
||||||
|
if (!$order) {
|
||||||
|
$blockReason = 'Pacchetto non trovato.';
|
||||||
|
} elseif (BookingRules::isExpired($order)) {
|
||||||
|
$blockReason = 'Questo pacchetto è scaduto.';
|
||||||
} else {
|
} else {
|
||||||
$currentMonthStart = date("Y-m-01");
|
$remaining = BookingRules::remaining($order);
|
||||||
}
|
if ($remaining <= 0) {
|
||||||
|
$blockReason = 'Hai già prenotato tutte le lezioni di questo pacchetto.';
|
||||||
$currentMonthEnd = date("Y-m-t", strtotime($currentMonthStart));
|
|
||||||
|
|
||||||
$bookedclass->setQuery("SELECT * FROM serviceschedule
|
|
||||||
LEFT JOIN service ON serviceschedule.idservice = service.idservice
|
|
||||||
WHERE serviceschedule.dateschedule BETWEEN '$currentMonthStart' AND DATE_ADD('$currentMonthEnd', INTERVAL 1 DAY) ORDER BY serviceschedule.dateschedule");
|
|
||||||
$bookedclass->execute();
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID dell'utente per il quale vuoi filtrare gli ordini
|
|
||||||
$userid = 1;
|
|
||||||
|
|
||||||
// Query per ottenere la somma dei ticket per ogni ordine dell'utente
|
|
||||||
$query = "SELECT iduser, idorderbook, SUM(nticket) as total_tickets
|
|
||||||
FROM orderbook
|
|
||||||
WHERE iduser = $userid
|
|
||||||
GROUP BY iduser";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
die("Query fallita: " . $conn->error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($result->num_rows > 0) {
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$idOrdine = $row["idorderbook"];
|
|
||||||
$totalTickets = $row["total_tickets"];
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$totalTickets = 0; // Imposta a zero se non ci sono righe nella query
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$conn->close();
|
/* Mese da visualizzare */
|
||||||
|
$monthParam = $_GET['prev_month'] ?? $_GET['next_month'] ?? '';
|
||||||
|
$currentMonthStart = preg_match('/^\d{4}-\d{2}$/', $monthParam) ? $monthParam . '-01' : date('Y-m-01');
|
||||||
|
$currentMonthEnd = date('Y-m-t', strtotime($currentMonthStart));
|
||||||
|
|
||||||
|
/* Lezioni disponibili */
|
||||||
|
$classes = [];
|
||||||
|
$expiry = $order['expireon'] ?? null;
|
||||||
|
|
||||||
|
if (!$blockReason) {
|
||||||
|
$allowed = BookingRules::allowedServices((int) $order['idservice']);
|
||||||
|
$ph = implode(',', array_fill(0, count($allowed), '?'));
|
||||||
|
$sql = "SELECT ss.idserviceschedule, ss.idservice, ss.dateschedule,
|
||||||
|
s.servicename, s.maxcapacity, s.colorclass,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b
|
||||||
|
WHERE b.idserviceschedule = ss.idserviceschedule AND b.status IN ('booked','pending')) AS occupied,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b2
|
||||||
|
WHERE b2.idserviceschedule = ss.idserviceschedule AND b2.iduser = ? AND b2.status <> 'cancelled') AS mine
|
||||||
|
FROM serviceschedule ss
|
||||||
|
JOIN service s ON s.idservice = ss.idservice
|
||||||
|
WHERE ss.idschool = ?
|
||||||
|
AND ss.idservice IN ($ph)
|
||||||
|
AND ss.dateschedule > NOW()
|
||||||
|
AND ss.dateschedule BETWEEN ? AND DATE_ADD(?, INTERVAL 1 DAY)"
|
||||||
|
. ($expiry ? " AND ss.dateschedule <= ?" : "") . "
|
||||||
|
ORDER BY ss.dateschedule";
|
||||||
|
$params = array_merge([$iduserlogin, $idschool], $allowed, [$currentMonthStart, $currentMonthEnd]);
|
||||||
|
if ($expiry) {
|
||||||
|
$params[] = $expiry . ' 23:59:59';
|
||||||
|
}
|
||||||
|
$st = $pdo->prepare($sql);
|
||||||
|
$st->execute($params);
|
||||||
|
$classes = $st->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
$waitingEnabled = BookingRules::waitingListEnabled();
|
||||||
|
$schoolAddress = implode(', ', array_filter([
|
||||||
|
trim((string) ($schoolData['address'] ?? '')),
|
||||||
|
trim((string) ($schoolData['city'] ?? '')),
|
||||||
|
]));
|
||||||
|
|
||||||
|
$italianMonths = [
|
||||||
|
"January" => "Gennaio",
|
||||||
|
"February" => "Febbraio",
|
||||||
|
"March" => "Marzo",
|
||||||
|
"April" => "Aprile",
|
||||||
|
"May" => "Maggio",
|
||||||
|
"June" => "Giugno",
|
||||||
|
"July" => "Luglio",
|
||||||
|
"August" => "Agosto",
|
||||||
|
"September" => "Settembre",
|
||||||
|
"October" => "Ottobre",
|
||||||
|
"November" => "Novembre",
|
||||||
|
"December" => "Dicembre",
|
||||||
|
];
|
||||||
|
$monthLabel = $italianMonths[date('F', strtotime($currentMonthStart))] . ' ' . date('Y', strtotime($currentMonthStart));
|
||||||
|
$navBase = 'bookingpanelorder.php?idorder=' . $idorder;
|
||||||
|
$prevLink = $navBase . '&prev_month=' . date('Y-m', strtotime('-1 month', strtotime($currentMonthStart)));
|
||||||
|
$nextLink = $navBase . '&next_month=' . date('Y-m', strtotime('+1 month', strtotime($currentMonthStart)));
|
||||||
?>
|
?>
|
||||||
<?php //check tickets
|
|
||||||
// Connessione al database
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
if ($conn->connect_error) {
|
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID dell'utente per il quale si desidera eseguire la query
|
|
||||||
$iduser = 1; // Sostituisci con l'ID utente desiderato
|
|
||||||
|
|
||||||
// Data e ora attuali
|
|
||||||
$currentDateTime = date("Y-m-d H:i:s");
|
|
||||||
|
|
||||||
// Query per contare i record con data e ora passate e future
|
|
||||||
$query = "SELECT COUNT(*) AS total,
|
|
||||||
SUM(CASE WHEN serviceschedule.dateschedule <= '$currentDateTime' THEN 1 ELSE 0 END) AS passed,
|
|
||||||
SUM(CASE WHEN serviceschedule.dateschedule > '$currentDateTime' THEN 1 ELSE 0 END) AS future
|
|
||||||
FROM bookingclass
|
|
||||||
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
|
|
||||||
WHERE bookingclass.iduser = $iduser";
|
|
||||||
|
|
||||||
$result = $conn->query($query);
|
|
||||||
if ($result) {
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
$totalRecords = $row['total'];
|
|
||||||
$passedRecords = $row['passed'];
|
|
||||||
$futureRecords = $row['future'];
|
|
||||||
}
|
|
||||||
// Chiusura della connessione
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="it">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>YogiBook - Prenotazioni YogaSoul</title>
|
<title>YogiBook - <?php echo e($schoolname); ?></title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta content="YogiBook - Prenotazione facile YogaSOul" name="description" />
|
|
||||||
<meta content="Advanced Creative Solutions" name="author" />
|
|
||||||
<!-- App favicon -->
|
|
||||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||||
|
|
||||||
<!-- Bootstrap Css -->
|
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
||||||
<!-- Icons Css -->
|
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
||||||
<!-- App Css-->
|
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" /><?php include('include/schooltheme.php'); ?>
|
||||||
<link href="assets/css/app.min.css" id="app-style" rel="stylesheet" type="text/css" />
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.custom-card {
|
.custom-card {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
box-shadow: 0 3px 16px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 3px 16px rgba(0, 0, 0, .06);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
|
||||||
transition: box-shadow 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card:hover {
|
|
||||||
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-date-box {
|
.custom-date-box {
|
||||||
@@ -234,7 +132,7 @@ $conn->close();
|
|||||||
.custom-month {
|
.custom-month {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: .05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-event-details {
|
.custom-event-details {
|
||||||
@@ -244,7 +142,6 @@ $conn->close();
|
|||||||
padding: 18px 22px;
|
padding: 18px 22px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-left: 20px solid #ccc;
|
border-left: 20px solid #ccc;
|
||||||
/* colore impostato inline per ogni card in base allo stato */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-heading {
|
.custom-heading {
|
||||||
@@ -260,32 +157,52 @@ $conn->close();
|
|||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-actions {
|
.booking-button {
|
||||||
display: none;
|
display: inline-block;
|
||||||
flex-direction: row;
|
|
||||||
gap: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-card.expanded .custom-actions {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-action-button {
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 7px 14px;
|
padding: 8px 16px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: #eef2f7;
|
background: #eef2f7;
|
||||||
color: #374151;
|
color: #374151;
|
||||||
cursor: pointer;
|
margin-top: 10px;
|
||||||
transition: filter 0.15s;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-action-button:hover {
|
.booking-button.go {
|
||||||
filter: brightness(0.94);
|
background: #1ebf73;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.booking-button.wait {
|
||||||
|
background: #d1698a;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-navigation {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
margin: 10px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-navigation h2 {
|
||||||
|
margin: 0;
|
||||||
|
min-width: 220px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.from-box {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 3px 16px rgba(0, 0, 0, .06);
|
||||||
|
padding: 18px 22px;
|
||||||
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -304,504 +221,113 @@ $conn->close();
|
|||||||
.custom-day {
|
.custom-day {
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-month {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style>
|
|
||||||
.month-navigation {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.month-nav-button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-month {
|
|
||||||
font-size: 24px;
|
|
||||||
margin: 0 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
function confirmDelete(id, deletePageUrl) {
|
|
||||||
Swal.fire({
|
|
||||||
title: "Sei sicuro?",
|
|
||||||
text: "Questa prenotazione verrà cancellata definitivamente! Ricordati poi di riprogrammare la tua lezione!",
|
|
||||||
icon: "warning",
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonColor: "#d33",
|
|
||||||
cancelButtonColor: "#3085d6",
|
|
||||||
confirmButtonText: "Sì, cancella!",
|
|
||||||
cancelButtonText: "Annulla"
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
// Reindirizza direttamente alla pagina di cancellazione con l'ID come parametro.
|
|
||||||
window.location.href = `deleteclass.php?id=${id}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.pastel-color {
|
|
||||||
border: 1px solid #D1C4CC;
|
|
||||||
padding: 0px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 20px;
|
|
||||||
/* Spazio tra i box */
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.blue {
|
|
||||||
background-color: #D4E1F1;
|
|
||||||
/* Azzurro pastello */
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.green {
|
|
||||||
background-color: #FFD8B5;
|
|
||||||
/* Verde pastello */
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.pink {
|
|
||||||
background-color: #C3E6CB;
|
|
||||||
/* Rosa pastello */
|
|
||||||
}
|
|
||||||
|
|
||||||
.pastel-color.purple {
|
|
||||||
background-color: #F4CCCC;
|
|
||||||
/* Viola pastello */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.pastel-color {
|
|
||||||
margin-right: 0;
|
|
||||||
/* Rimuovi lo spazio tra i box */
|
|
||||||
margin-bottom: 20px;
|
|
||||||
/* Spazio tra i box */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style>
|
|
||||||
.booking-details {
|
|
||||||
margin-top: 10px;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.booking-table td {
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button {
|
|
||||||
background-color: #ff6347;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
padding: 5px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-button:hover {
|
|
||||||
background-color: #d64937;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- <body data-layout="horizontal"> -->
|
|
||||||
|
|
||||||
<!-- Begin page -->
|
|
||||||
<div id="layout-wrapper">
|
<div id="layout-wrapper">
|
||||||
|
|
||||||
<!-- Top Bar -->
|
|
||||||
<header id="page-topbar" class="isvertical-topbar">
|
<header id="page-topbar" class="isvertical-topbar">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<!-- LOGO -->
|
|
||||||
<?php include('include/logoarea.php'); ?>
|
<?php include('include/logoarea.php'); ?>
|
||||||
|
|
||||||
<button type="button" class="btn btn-sm px-3 font-size-24 header-item waves-effect vertical-menu-btn">
|
<button type="button" class="btn btn-sm px-3 font-size-24 header-item waves-effect vertical-menu-btn">
|
||||||
<i class="bx bx-menu align-middle"></i>
|
<i class="bx bx-menu align-middle"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- start page title -->
|
|
||||||
<div class="page-title-box align-self-center d-none d-md-block">
|
<div class="page-title-box align-self-center d-none d-md-block">
|
||||||
<h4 class="page-title mb-0">Riprogramma la tua lezione</h4>
|
<h4 class="page-title mb-0">Prenota le tue lezioni</h4>
|
||||||
</div>
|
</div>
|
||||||
<!-- end page title -->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
|
<?php include('include/schoolswitcher.php'); ?><?php include('include/languageselection.php'); ?>
|
||||||
<?php include('include/languageselection.php'); ?>
|
|
||||||
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button type="button" class="btn header-item noti-icon"
|
|
||||||
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<i class="bx bx-search icon-sm align-middle"></i>
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-end p-0">
|
|
||||||
<form class="p-2">
|
|
||||||
<div class="search-box">
|
|
||||||
<div class="position-relative">
|
|
||||||
<input type="text" class="form-control rounded bg-light border-0" placeholder="Search...">
|
|
||||||
<i class="bx bx-search search-icon"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
<?php include('include/profiletopbar.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<?php include('include/sidebar.php'); ?>
|
<?php include('include/sidebar.php'); ?>
|
||||||
|
|
||||||
<header class="ishorizontal-topbar">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<div class="d-flex">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="topnav">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<nav class="navbar navbar-light navbar-expand-lg topnav-menu">
|
|
||||||
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- ============================================================== -->
|
|
||||||
<!-- Start right Content here -->
|
|
||||||
<!-- ============================================================== -->
|
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
|
<a href="selectorder.php" class="d-inline-block mb-3"><i class="fas fa-arrow-left me-1"></i> Torna ai pacchetti</a>
|
||||||
|
|
||||||
<?php
|
<?php if ($blockReason) : ?>
|
||||||
$toprogram = $totalTickets - $passedRecords - $futureRecords;
|
<div class="alert alert-warning"><i class="fas fa-circle-info me-1"></i> <?php echo e($blockReason); ?></div>
|
||||||
|
<?php else : ?>
|
||||||
|
|
||||||
?>
|
<div class="from-box">
|
||||||
<!-- container-fluid -->
|
<div class="text-muted" style="font-size:13px;">Pacchetto</div>
|
||||||
</div>
|
<strong style="font-size:17px;"><?php echo e($order['servicename'] ?: 'Pacchetto'); ?></strong>
|
||||||
|
<div class="text-muted mt-1" style="font-size:13px;">
|
||||||
|
Lezioni da prenotare: <strong style="color:#1a7f52;"><?php echo $remaining; ?></strong>
|
||||||
<div class="container-fluid">
|
<?php if ($expiry) : ?> · Valido fino al <?php echo e(date('d-m-Y', strtotime($expiry))); ?><?php endif; ?>
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<div class="row mb-2">
|
|
||||||
<div class="col-xl-3 col-md-12">
|
|
||||||
<div class="pb-3 pb-xl-0">
|
|
||||||
<form class="email-search">
|
|
||||||
<div class="position-relative">
|
|
||||||
<h3>Riprogrammazione Lezione</h3>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xl-9 col-md-12">
|
|
||||||
<div class="text-sm-end">
|
|
||||||
<?php if ($toprogram > 0) {
|
|
||||||
echo '<button type="button" class="btn btn-info btn-rounded waves-effect waves-light mb-2 me-2" data-bs-toggle="modal" data-bs-target=".create-task"><i class="mdi mdi-plus me-1"></i> Programma Lezioni</button>';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<button type="button" class="btn btn-success btn-rounded waves-effect waves-light mb-2 me-2" data-bs-toggle="modal" data-bs-target=".create-task"><i class="mdi mdi-plus me-1"></i> Acquista Pacchetto Lezioni</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- container-fluid -->
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<!-- starts cards -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Aggiungi le frecce per la navigazione tra i mesi -->
|
|
||||||
<?php
|
|
||||||
$italianMonths = [
|
|
||||||
"January" => "Gennaio",
|
|
||||||
"February" => "Febbraio",
|
|
||||||
"March" => "Marzo",
|
|
||||||
"April" => "Aprile",
|
|
||||||
"May" => "Maggio",
|
|
||||||
"June" => "Giugno",
|
|
||||||
"July" => "Luglio",
|
|
||||||
"August" => "Agosto",
|
|
||||||
"September" => "Settembre",
|
|
||||||
"October" => "Ottobre",
|
|
||||||
"November" => "Novembre",
|
|
||||||
"December" => "Dicembre"
|
|
||||||
];
|
|
||||||
|
|
||||||
?>
|
|
||||||
<div class="month-navigation">
|
<div class="month-navigation">
|
||||||
|
<a href="<?php echo e($prevLink); ?>"><i class="fas fa-chevron-left fa-2x"></i></a>
|
||||||
<a href="?prev_month=<?php echo date('Y-m', strtotime('-1 month', strtotime($currentMonthStart))); ?>&idserviceordered=<?php echo $idserviceordered; ?>&idorder=<?php echo $idorder; ?>" class="arrow-link">
|
<h2><?php echo e($monthLabel); ?></h2>
|
||||||
<i class="fas fa-chevron-left fa-2x"></i>
|
<a href="<?php echo e($nextLink); ?>"><i class="fas fa-chevron-right fa-2x"></i></a>
|
||||||
</a>
|
|
||||||
|
|
||||||
<h2><?php echo $italianMonths[date("F", strtotime($currentMonthStart))] . ' ' . date("Y", strtotime($currentMonthStart)); ?></h2>
|
|
||||||
<a href="?next_month=<?php echo date('Y-m', strtotime('+1 month', strtotime($currentMonthStart))); ?>&idserviceordered=<?php echo $idserviceordered; ?>&idorder=<?php echo $idorder; ?>" class="arrow-link">
|
|
||||||
<i class="fas fa-chevron-right fa-2x"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if (empty($classes)) : ?>
|
||||||
|
<p class="text-center text-muted">Nessuna lezione disponibile in questo mese<?php echo $expiry ? ' entro la scadenza del pacchetto' : ''; ?>.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php foreach ($classes as $c) :
|
||||||
|
$d = new DateTime($c['dateschedule']);
|
||||||
|
$max = (int) $c['maxcapacity'];
|
||||||
<?php
|
$occ = (int) $c['occupied'];
|
||||||
$wa_startindex = 0;
|
$free = $max <= 0 || $occ < $max;
|
||||||
|
$mine = (int) $c['mine'] > 0;
|
||||||
if ($bookedclass->TotalRows == 0) {
|
$boxColor = $mine ? '#FF6609' : ($free ? '#1ebf73' : '#d1698a');
|
||||||
echo "<p>Classi non presenti per questo mese</p>";
|
$link = 'bookandgo.php?idorder=' . $idorder . '&idnewbooking=' . (int) $c['idserviceschedule'];
|
||||||
} else {
|
|
||||||
while (!$bookedclass->atEnd()) {
|
|
||||||
$wa_startindex = $bookedclass->Index;
|
|
||||||
?>
|
?>
|
||||||
<?php
|
<div class="custom-card">
|
||||||
// Data dalla variabile $bookedclass->getColumnVal("dateschedule")
|
<div class="custom-date-box" style="background:<?php echo $boxColor; ?>;">
|
||||||
$dateschedule = $bookedclass->getColumnVal("dateschedule");
|
<div class="custom-day"><?php echo $d->format('d'); ?></div>
|
||||||
|
<div class="custom-month"><?php echo e($italianMonths[$d->format('F')]); ?></div>
|
||||||
// Converti la data in un oggetto DateTime
|
</div>
|
||||||
$dateObj = new DateTime($dateschedule);
|
<div class="custom-event-details" style="border-left-color:<?php echo e($mine ? '#FF6609' : ($free ? ($c['colorclass'] ?: '#1ebf73') : '#d1698a')); ?>;">
|
||||||
|
<h2 class="custom-heading"><?php echo e($c['servicename']); ?> · <?php echo $occ; ?>/<?php echo $max; ?></h2>
|
||||||
// Estrai il giorno e il mese in italiano
|
<p class="custom-paragraph">Quando: <?php echo e($d->format('d-m-Y H:i')); ?></p>
|
||||||
$dayInItalian = $dateObj->format("d");
|
<?php if ($schoolAddress !== '') : ?><p class="custom-paragraph">Luogo: <?php echo e($schoolAddress); ?></p><?php endif; ?>
|
||||||
$monthInItalian = $dateObj->format("F");
|
<div>
|
||||||
|
<?php if ($mine) : ?>
|
||||||
// Mappa dei nomi dei mesi in italiano
|
<span class="booking-button"><i class="fa fa-check"></i> Sei già prenotata/o</span>
|
||||||
$italianMonths = [
|
<?php elseif ($free) : ?>
|
||||||
"January" => "Gennaio",
|
<a class="booking-button go" href="<?php echo e($link); ?>"><i class="fas fa-arrow-circle-right"></i> Prenota</a>
|
||||||
"February" => "Febbraio",
|
<?php elseif ($waitingEnabled) : ?>
|
||||||
"March" => "Marzo",
|
<a class="booking-button wait" href="<?php echo e($link); ?>"><i class="fas fa-hourglass-half"></i> Mettiti in lista d'attesa</a>
|
||||||
"April" => "Aprile",
|
<?php else : ?>
|
||||||
"May" => "Maggio",
|
<span class="booking-button"><i class="fa fa-stop"></i> Classe piena</span>
|
||||||
"June" => "Giugno",
|
<?php endif; ?>
|
||||||
"July" => "Luglio",
|
|
||||||
"August" => "Agosto",
|
|
||||||
"September" => "Settembre",
|
|
||||||
"October" => "Ottobre",
|
|
||||||
"November" => "Novembre",
|
|
||||||
"December" => "Dicembre"
|
|
||||||
];
|
|
||||||
|
|
||||||
// Sostituisci il nome del mese con la versione italiana
|
|
||||||
$monthInItalian = $italianMonths[$monthInItalian];
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
// Data dalla variabile $bookedclass->getColumnVal("dateschedule")
|
|
||||||
$dateschedule = $bookedclass->getColumnVal("dateschedule");
|
|
||||||
|
|
||||||
// Converti la data in un oggetto DateTime
|
|
||||||
$dateObj = new DateTime($dateschedule);
|
|
||||||
|
|
||||||
// Formatta la data nel nuovo formato desiderato
|
|
||||||
$newDateFormat = $dateObj->format("d-m-Y H:i");
|
|
||||||
|
|
||||||
// Calculate the time difference in hours
|
|
||||||
$currentTime = new DateTime();
|
|
||||||
$classTime = new DateTime($dateschedule);
|
|
||||||
$timeDifference = $classTime->diff($currentTime);
|
|
||||||
$hoursDifference = $timeDifference->h + $timeDifference->days * 24;
|
|
||||||
|
|
||||||
// Check if the time difference is less than 6 hours
|
|
||||||
$timetocancel = $optionquery->getColumnVal("maxbeforetimecancell");
|
|
||||||
$canBeDeleted = ($hoursDifference >= $timetocancel);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
|
||||||
<?php $mysqli = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
// Esegui una nuova query per ottenere le persone prenotate per l'evento corrente
|
|
||||||
$eventId = $bookedclass->getColumnVal("idserviceschedule");
|
|
||||||
$bookingQuery = "SELECT iduser FROM bookingclass
|
|
||||||
WHERE bookingclass.idserviceschedule = $eventId AND bookingclass.status='booked'";
|
|
||||||
$bookingResult = $mysqli->query($bookingQuery);
|
|
||||||
|
|
||||||
// Calcola il numero di persone prenotate
|
|
||||||
$countPersons = $bookingResult->num_rows;
|
|
||||||
|
|
||||||
?>
|
|
||||||
<?php // check if service possible to bookedclass
|
|
||||||
|
|
||||||
// Esempio: Simula il valore di $bookedclass->getColumnVal("servicename")
|
|
||||||
$cardservice = $bookedclass->getColumnVal("idservice");
|
|
||||||
|
|
||||||
// Verifica se il valore di $cardservice è presente nell'array $idassociateservices
|
|
||||||
if (in_array($cardservice, $idassociateservices)) {
|
|
||||||
// Il valore è presente, esegui il codice successivo
|
|
||||||
|
|
||||||
?>
|
|
||||||
<?php
|
|
||||||
$maxcapacity = $bookedclass->getColumnVal("maxcapacity");
|
|
||||||
$freeplace = $maxcapacity - $countPersons;
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php //query check active bookingclass
|
|
||||||
// Crea la connessione al database
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
|
||||||
// Variabili dei dati da verificare
|
|
||||||
$idcheckservice = $bookedclass->getColumnVal("idserviceschedule"); // Sostituisci con il tuo valore
|
|
||||||
$iduser = $iduserlog; // Sostituisci con il tuo valore
|
|
||||||
|
|
||||||
// Query per verificare l'esistenza del record
|
|
||||||
$query = "SELECT * FROM bookingclass WHERE idserviceschedule = $idcheckservice AND iduser = $iduser";
|
|
||||||
$resultcheck = $conn->query($query);
|
|
||||||
|
|
||||||
if ($resultcheck->num_rows > 0) {
|
|
||||||
$alreadybooked = 'Y'; // record found
|
|
||||||
} else {
|
|
||||||
$alreadybooked = 'N';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="custom-card" onclick="toggleCard(this)">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php if ($alreadybooked == 'Y') { ?>
|
|
||||||
<div class="custom-date-box" style="background-color:#FF6609">
|
|
||||||
<?php } elseif ($freeplace > 0) { ?><div class="custom-date-box" style="background-color:#1ebf73">
|
|
||||||
<?php } else { ?><div class="custom-date-box" style="background-color:#9C9C9C"><?php } ?>
|
|
||||||
<div class="custom-day"><?php echo $dayInItalian; ?></div>
|
|
||||||
<div class="custom-month"><?php echo $monthInItalian; ?></div>
|
|
||||||
</div>
|
|
||||||
<?php if ($alreadybooked == 'Y') { ?>
|
|
||||||
<div class="custom-event-details" style="background-color:#FFAC7A;border-left-color:#FF6609">
|
|
||||||
<?php } elseif ($freeplace > 0) { ?>
|
|
||||||
<div class="custom-event-details" style="border-left-color:<?php echo ($bookedclass->getColumnVal("colorclass")); ?>">
|
|
||||||
<?php } else { ?><div class="custom-event-details" style="background-color:#CDCDCD;border-left-color:#9C9C9C"><?php } ?>
|
|
||||||
<h2 class="custom-heading"><?php echo ($bookedclass->getColumnVal("servicename")); ?> -<?php echo $countPersons; ?>/<?php echo ($bookedclass->getColumnVal("maxcapacity")); ?></h2>
|
|
||||||
<p class="custom-paragraph">Quando: <?php echo $newDateFormat; ?></p>
|
|
||||||
<p class="custom-paragraph">Luogo: via Valassina 62/B Seregno - Sala Contesto Yoga</p>
|
|
||||||
<?php $idnewbooking = $bookedclass->getColumnVal("idserviceschedule"); ?>
|
|
||||||
<?php $idservicenew = $bookedclass->getColumnVal("idservice"); ?>
|
|
||||||
<!-- Mostra l'elenco delle persone prenotate solo se ce ne sono -->
|
|
||||||
|
|
||||||
<div class="booking-details">
|
|
||||||
<?php if ($alreadybooked == 'Y') { ?>
|
|
||||||
<button class="booking-button"><i class="fa fa-check"></i> Sei già prenotata/o</button>
|
|
||||||
<?php } elseif ($freeplace > 0) {
|
|
||||||
?>
|
|
||||||
<a href="bookandgo.php?idpreviousbooking=<?php echo '0'; ?>&idorder=<?php echo $idorder; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>" ?><button class="booking-button"><i class="fas fa-arrow-circle-right"></i> Riprogramma Classe</button></a>
|
|
||||||
<?php } else { ?>
|
|
||||||
<a href="bookandgo.php?idpreviousbooking=0&idorder=<?php echo $idorder; ?>&idservicenew=<?php echo $idservicenew; ?>&idnewbooking=<?php echo $idnewbooking; ?>&iduser=<?php echo $iduserlogin; ?>"><button class="booking-button" style="background-color:#f0ad4e;color:#fff;"><i class="fas fa-hourglass-half"></i> Mettiti in lista d'attesa</button></a>
|
|
||||||
<?php } ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
$bookedclass->moveNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bookedclass->moveFirst(); // Ritorna all'inizio del recordset
|
|
||||||
unset($wa_startindex);
|
|
||||||
unset($wa_repeatcount);
|
|
||||||
?>
|
|
||||||
<!-- Aggiungi altre card qui con le stesse classi -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleCard(card) {
|
|
||||||
card.classList.toggle("expanded");
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- End Page-content -->
|
|
||||||
|
|
||||||
<?php include('include/footer.php'); ?>
|
|
||||||
</div>
|
|
||||||
<!-- end main content-->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- END layout-wrapper -->
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($classes)) : ?>
|
||||||
|
<div class="month-navigation">
|
||||||
|
<a href="<?php echo e($prevLink); ?>"><i class="fas fa-chevron-left fa-2x"></i></a>
|
||||||
|
<h2><?php echo e($monthLabel); ?></h2>
|
||||||
|
<a href="<?php echo e($nextLink); ?>"><i class="fas fa-chevron-right fa-2x"></i></a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<?php include('include/footer.php'); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
||||||
|
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
||||||
|
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
||||||
<!-- JAVASCRIPT -->
|
<script src="assets/js/app.js"></script>
|
||||||
<script src="assets/libs/bootstrap/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="assets/libs/metismenujs/metismenujs.min.js"></script>
|
|
||||||
<script src="assets/libs/simplebar/simplebar.min.js"></script>
|
|
||||||
<script src="assets/libs/eva-icons/eva.min.js"></script>
|
|
||||||
|
|
||||||
<script src="assets/js/app.js"></script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,60 +1,37 @@
|
|||||||
<?php
|
<?php
|
||||||
ini_set('display_errors', '1');
|
// Buffer: scarta l'HTML degli include, risposta JSON pura
|
||||||
ini_set('display_startup_errors', '1');
|
ob_start();
|
||||||
error_reporting(E_ALL);
|
require_once('include/headscript.php');
|
||||||
include('Connections/bkngstm.php');
|
require_once('class/OrderRules.php');
|
||||||
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
/**
|
||||||
if ($conn->connect_error) {
|
* Scadenza proposta per un ordine della scuola corrente (per il modale "Propaga").
|
||||||
die(json_encode(['error' => 'Connessione al database fallita']));
|
* GET: idorder. Risposta: { expiry_date: 'Y-m-d' } oppure { error: '...' }.
|
||||||
}
|
*/
|
||||||
|
function jsonOut(array $payload, int $code = 200): void
|
||||||
if (isset($_GET['idorder'])) {
|
{
|
||||||
$idorder = $_GET['idorder'];
|
if (ob_get_length() !== false) {
|
||||||
|
ob_end_clean();
|
||||||
// Recupera i dati necessari dall'ordine
|
|
||||||
$order_query = "SELECT idservice, quantityclass, first_lesson_date FROM orderbook WHERE idorderbook = ?";
|
|
||||||
$stmt_order = $conn->prepare($order_query);
|
|
||||||
$stmt_order->bind_param("i", $idorder);
|
|
||||||
$stmt_order->execute();
|
|
||||||
$order_result = $stmt_order->get_result();
|
|
||||||
|
|
||||||
if ($order_result->num_rows > 0) {
|
|
||||||
$order_row = $order_result->fetch_assoc();
|
|
||||||
$service_id = $order_row['idservice'];
|
|
||||||
$quantity_class = $order_row['quantityclass'];
|
|
||||||
$first_lesson_date = $order_row['first_lesson_date'];
|
|
||||||
|
|
||||||
// Recupera expirylessons da expiryparameter
|
|
||||||
$expiry_lessons_query = "SELECT expirylessons FROM expiryparameter WHERE quantityclass = ?";
|
|
||||||
$stmt_expiry_lessons = $conn->prepare($expiry_lessons_query);
|
|
||||||
$stmt_expiry_lessons->bind_param("i", $quantity_class);
|
|
||||||
$stmt_expiry_lessons->execute();
|
|
||||||
$expiry_lessons_result = $stmt_expiry_lessons->get_result();
|
|
||||||
|
|
||||||
if ($expiry_lessons_result->num_rows > 0) {
|
|
||||||
$expiry_row = $expiry_lessons_result->fetch_assoc();
|
|
||||||
$expirylessons = $expiry_row['expirylessons'];
|
|
||||||
|
|
||||||
// expirylessons = numero di SETTIMANE di validità (es. 12 ticket -> 15 settimane)
|
|
||||||
// La scadenza si calcola SEMPRE dalla prima lezione, a prescindere
|
|
||||||
// dalle date presenti in calendario.
|
|
||||||
try {
|
|
||||||
$base = new DateTime($first_lesson_date);
|
|
||||||
$base->modify('+' . (int)$expirylessons . ' weeks');
|
|
||||||
$expireon = $base->format('Y-m-d');
|
|
||||||
echo json_encode(['expiry_date' => $expireon]);
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
echo json_encode(['error' => 'Data prima lezione non valida']);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo json_encode(['error' => 'Nessun record in expiryparameter per quantityclass: ' . $quantity_class]);
|
|
||||||
}
|
|
||||||
$stmt_expiry_lessons->close();
|
|
||||||
} else {
|
|
||||||
echo json_encode(['error' => 'Ordine non trovato']);
|
|
||||||
}
|
}
|
||||||
$stmt_order->close();
|
http_response_code($code);
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$conn->close();
|
if (!SchoolContext::isSchoolAdmin()) {
|
||||||
|
jsonOut(['error' => 'Accesso non autorizzato.'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$order = OrderRules::find((int) ($_GET['idorder'] ?? 0));
|
||||||
|
if (!$order) {
|
||||||
|
jsonOut(['error' => 'Ordine non trovato.'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$expiry = OrderRules::calculateExpiry($order);
|
||||||
|
|
||||||
|
// Nessun calcolo possibile: proponi 3 mesi dalla prima lezione, l'admin può correggere
|
||||||
|
jsonOut([
|
||||||
|
'expiry_date' => $expiry ?: date('Y-m-d', strtotime(($order['first_lesson_date'] ?: date('Y-m-d')) . ' +3 months')),
|
||||||
|
'calculated' => $expiry !== null,
|
||||||
|
]);
|
||||||
|
|||||||
@@ -1,34 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
<?php require_once('Connections/bkngstm.php');
|
/**
|
||||||
|
* Rimuove un'associazione tra classi (solo scuola corrente).
|
||||||
|
* GET: idassociateclass, id (classe principale, per il ritorno).
|
||||||
|
*/
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
$idassociateclass = (int) ($_GET['idassociateclass'] ?? 0);
|
||||||
|
$idmain = (int) ($_GET['id'] ?? 0);
|
||||||
|
|
||||||
// Verifica della connessione
|
if (SchoolScope::belongs('associateclass', $idassociateclass)) {
|
||||||
if ($conn->connect_error) {
|
$pdo->prepare("DELETE FROM associateclass WHERE idassociateclass = ? AND idschool = ?")
|
||||||
die("Connessione al database fallita: " . $conn->connect_error);
|
->execute([$idassociateclass, $idschool]);
|
||||||
|
header('Location: associate-services.php?id=' . $idmain . '&removed=1');
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifica se è stato passato l'id come parametro GET
|
header('Location: admin-services.php?message=notfound');
|
||||||
if (isset($_GET['idassociateclass'])) {
|
exit;
|
||||||
$idassociateclass = $_GET['idassociateclass'];
|
|
||||||
|
|
||||||
// Query per cancellare il record con l'id fornito dalla tabella associateclass
|
|
||||||
$deleteQuery = "DELETE FROM associateclass WHERE idassociateclass = $idassociateclass";
|
|
||||||
|
|
||||||
if ($conn->query($deleteQuery) === TRUE) {
|
|
||||||
// Chiusura della connessione
|
|
||||||
$conn->close();
|
|
||||||
|
|
||||||
// Redirect alla pagina associate-services.php con la variabile id come parametro GET
|
|
||||||
header("Location: associate-services.php?id=" . $_GET['id']);
|
|
||||||
exit();
|
|
||||||
} else {
|
|
||||||
echo "Errore durante la cancellazione del record: " . $conn->error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo "ID non fornito.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chiusura della connessione
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
|
|||||||
@@ -1,307 +1,203 @@
|
|||||||
<?php
|
<?php
|
||||||
// Connessione al database
|
require_once('include/headscript.php');
|
||||||
include('include/headscript.php');
|
require_once('class/SchoolMail.php');
|
||||||
require_once __DIR__ . '/class/mailer.php';
|
|
||||||
|
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
/**
|
||||||
use PHPMailer\PHPMailer\Exception;
|
* Gestione lezione dal link dell'email di promemoria.
|
||||||
|
* GET: idbookingclass, token [+ action=cancel per confermare la cancellazione]
|
||||||
|
* Il token identifica la prenotazione; la scuola è quella della lezione
|
||||||
|
* (non quella selezionata in sessione).
|
||||||
|
*/
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
// Riusa la connessione già aperta da bkngstm.php
|
function e($v): string
|
||||||
$conn = $bkngstm;
|
{
|
||||||
// Inizializza log
|
return htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
|
||||||
$logFile = 'cancella_prenotazione_log.txt';
|
|
||||||
$logMessage = "Esecuzione cancellazione: " . date('Y-m-d H:i:s') . "\n";
|
|
||||||
|
|
||||||
// Recupera parametri GET: idbookingclass e token
|
|
||||||
if (!isset($_GET['idbookingclass']) || !isset($_GET['token'])) {
|
|
||||||
$logMessage .= "Parametri mancanti: idbookingclass o token\n";
|
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
|
||||||
echo "<h1>Cancellazione non possibile</h1>";
|
|
||||||
echo "<p>Parametri mancanti.</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
$conn->close();
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitizza idbookingclass
|
$id = (int) ($_GET['idbookingclass'] ?? 0);
|
||||||
$idbookingclass = filter_var($_GET['idbookingclass'], FILTER_VALIDATE_INT);
|
$token = preg_replace('/[^a-zA-Z0-9\-]/', '', (string) ($_GET['token'] ?? ''));
|
||||||
$token = $_GET['token'];
|
|
||||||
|
|
||||||
if (!$idbookingclass) {
|
$bk = null;
|
||||||
$logMessage .= "Errore: idbookingclass non valido: " . $_GET['idbookingclass'] . "\n";
|
if ($id > 0 && $token !== '') {
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
$st = $pdo->prepare(
|
||||||
echo "<h1>Cancellazione non possibile</h1>";
|
"SELECT bc.idbookingclass, bc.idschool, bc.iduser, bc.status,
|
||||||
echo "<p>Parametro idbookingclass non valido.</p>";
|
ss.dateschedule, s.servicename, ob.expireon,
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
au.email, au.first_name
|
||||||
$conn->close();
|
FROM bookingclass bc
|
||||||
exit;
|
JOIN serviceschedule ss ON ss.idserviceschedule = bc.idserviceschedule
|
||||||
|
LEFT JOIN service s ON s.idservice = bc.idservice
|
||||||
|
LEFT JOIN orderbook ob ON ob.idorderbook = bc.idorder
|
||||||
|
LEFT JOIN auth_users au ON au.id = bc.iduser
|
||||||
|
WHERE bc.idbookingclass = ? AND bc.cancellation_token = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$id, $token]);
|
||||||
|
$bk = $st->fetch() ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifica validità: token corrisponde, lezione futura
|
$school = null;
|
||||||
$query = "SELECT bc.*, ob.expireon, au.email, au.first_name, s.servicename
|
if ($bk) {
|
||||||
FROM bookingclass bc
|
$st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ?");
|
||||||
LEFT JOIN orderbook ob ON bc.idorder = ob.idorderbook
|
$st->execute([(int) $bk['idschool']]);
|
||||||
LEFT JOIN auth_users au ON bc.iduser = au.id
|
$school = $st->fetch() ?: null;
|
||||||
LEFT JOIN service s ON bc.idservice = s.idservice
|
|
||||||
WHERE bc.idbookingclass = ?
|
|
||||||
AND bc.cancellation_token = ?
|
|
||||||
AND bc.status = 'booked'
|
|
||||||
AND bc.bookingstart > NOW()";
|
|
||||||
$stmt = $conn->prepare($query);
|
|
||||||
|
|
||||||
if (!$stmt) {
|
|
||||||
$logMessage .= "Errore preparazione query per ID $idbookingclass: " . $conn->error . "\n";
|
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
|
||||||
echo "<h1>Cancellazione non possibile</h1>";
|
|
||||||
echo "<p>Errore nella preparazione della query.</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
$conn->close();
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt->bind_param("is", $idbookingclass, $token);
|
$state = 'ask'; // ask | done | invalid | toolate
|
||||||
$stmt->execute();
|
$message = '';
|
||||||
$result = $stmt->get_result();
|
|
||||||
|
|
||||||
if ($result->num_rows === 0) {
|
if (!$bk || !$school || $bk['status'] !== 'booked') {
|
||||||
$checkQuery = "SELECT * FROM bookingclass
|
$state = 'invalid';
|
||||||
WHERE idbookingclass = ?
|
} elseif (!BookingRules::canCancel($bk['dateschedule'])) {
|
||||||
AND cancellation_token = ?
|
$state = 'toolate';
|
||||||
AND status = 'booked'
|
} elseif (($_GET['action'] ?? '') === 'cancel') {
|
||||||
AND bookingstart > NOW()";
|
$upd = $pdo->prepare(
|
||||||
$checkStmt = $conn->prepare($checkQuery);
|
"UPDATE bookingclass SET status = 'cancelled'
|
||||||
$checkStmt->bind_param("is", $idbookingclass, $token);
|
WHERE idbookingclass = ? AND cancellation_token = ? AND status = 'booked'"
|
||||||
$checkStmt->execute();
|
);
|
||||||
$checkResult = $checkStmt->get_result();
|
$upd->execute([$id, $token]);
|
||||||
|
|
||||||
if ($checkResult->num_rows > 0) {
|
if ($upd->rowCount() > 0) {
|
||||||
$row = $checkResult->fetch_assoc();
|
$lines = [
|
||||||
$bookingstart = $row['bookingstart'];
|
'La tua lezione <strong>' . e($bk['servicename'] ?: 'Lezione') . '</strong> del <strong>'
|
||||||
$lessonTime = new DateTime($bookingstart);
|
. date('d-m-Y H:i', strtotime($bk['dateschedule'])) . '</strong> è stata cancellata.',
|
||||||
$hour = (int)$lessonTime->format('H');
|
];
|
||||||
$minute = (int)$lessonTime->format('i');
|
if (!empty($bk['expireon'])) {
|
||||||
$isBefore1700 = ($hour < 17) || ($hour === 17 && $minute === 0);
|
$lines[] = 'Ricordati di riprenotarla entro la scadenza del tuo pacchetto: <strong>' . date('d-m-Y', strtotime($bk['expireon'])) . '</strong>.';
|
||||||
$logMessage .= "Tentativo di cancellazione fallito per ID $idbookingclass: orario oltre il limite (" . ($isBefore1700 ? "00:01" : "12:00") . ")\n";
|
|
||||||
echo "<h1>Cancellazione non possibile</h1>";
|
|
||||||
echo "<p>Non è possibile cancellare la lezione dopo le " . ($isBefore1700 ? "00:01" : "12:00") . " del giorno della lezione.</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
} else {
|
|
||||||
$logMessage .= "Tentativo di cancellazione fallito per ID $idbookingclass: link non valido o lezione non prenotata\n";
|
|
||||||
echo "<h1>Cancellazione non possibile</h1>";
|
|
||||||
echo "<p>Il link non è valido o la lezione non è prenotata.</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
}
|
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
|
||||||
$checkStmt->close();
|
|
||||||
$stmt->close();
|
|
||||||
$conn->close();
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
$bookingstart = $row['bookingstart'];
|
|
||||||
$newtimeformat = date("d-m-Y H:i", strtotime($bookingstart));
|
|
||||||
$expireon = $row['expireon'] ? date("d-m-Y", strtotime($row['expireon'])) : "sconosciuta";
|
|
||||||
$emailuser = $row['email'];
|
|
||||||
$firstname = $row['first_name'] ?? 'Utente';
|
|
||||||
$servicename = $row['servicename'] ?? 'Sconosciuta';
|
|
||||||
$iduser = $row['iduser'];
|
|
||||||
$idservice = $row['idservice'];
|
|
||||||
$idorderbook = $row['idorder'];
|
|
||||||
|
|
||||||
// Verifica il limite di cancellazione
|
|
||||||
$lessonTime = new DateTime($bookingstart);
|
|
||||||
$hour = (int)$lessonTime->format('H');
|
|
||||||
$minute = (int)$lessonTime->format('i');
|
|
||||||
$isBefore1700 = ($hour < 17) || ($hour === 17 && $minute === 0);
|
|
||||||
$currentTime = new DateTime();
|
|
||||||
$lessonDate = $lessonTime->format('Y-m-d');
|
|
||||||
|
|
||||||
if ($isBefore1700) {
|
|
||||||
$deadline = new DateTime("$lessonDate 00:01:00");
|
|
||||||
} else {
|
|
||||||
$deadline = new DateTime("$lessonDate 12:00:00");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($currentTime > $deadline) {
|
|
||||||
$logMessage .= "Tentativo di cancellazione fallito per ID $idbookingclass: orario oltre il limite (" . $deadline->format('Y-m-d H:i:s') . ")\n";
|
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
|
||||||
echo "<h1>Cancellazione non possibile</h1>";
|
|
||||||
echo "<p>Non è possibile cancellare la lezione dopo le " . ($isBefore1700 ? "00:01" : "12:00") . " del giorno della lezione.</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
$stmt->close();
|
|
||||||
$conn->close();
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gestisci azione di cancellazione
|
|
||||||
if (isset($_GET['action']) && $_GET['action'] === 'cancel') {
|
|
||||||
$updateQuery = "UPDATE bookingclass
|
|
||||||
SET status = 'cancelled'
|
|
||||||
WHERE idbookingclass = ? AND cancellation_token = ?";
|
|
||||||
$updateStmt = $conn->prepare($updateQuery);
|
|
||||||
$updateStmt->bind_param("is", $idbookingclass, $token);
|
|
||||||
$updateStmt->execute();
|
|
||||||
|
|
||||||
if (!filter_var($emailuser, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$logMessage .= "Email non valida per ID $idbookingclass: $emailuser\n";
|
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
|
||||||
echo "<h1>Cancellazione confermata</h1>";
|
|
||||||
echo "<p>La lezione del $newtimeformat è stata cancellata con successo, ma non è stato possibile inviare l'email di conferma.</p>";
|
|
||||||
echo "<p>Ricordati di riprenotare entro la scadenza del tuo abbonamento ($expireon).</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
$stmt->close();
|
|
||||||
$conn->close();
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cancellationDeadline = $isBefore1700 ? "00:01" : "12:00";
|
|
||||||
$messagecancel = "<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 18px; line-height: 34.2px;'><strong>Ciao $firstname,</strong></span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>La tua lezione ($servicename) del $newtimeformat è stata cancellata con successo!</span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Hai cancellato la lezione entro il limite delle $cancellationDeadline del giorno della lezione.</span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Ricordati di riprenotare entro la scadenza del tuo abbonamento ($expireon).</span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Per vedere e gestire le tue lezioni clicca qui: <a href='https://yogibook.yogasoul.it'>YogiBook</a></span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Ci vediamo sul tappetino!</span></p>
|
|
||||||
<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>Il Team Yogasoul</span></p>";
|
|
||||||
|
|
||||||
$messageedit = $messagecancel;
|
|
||||||
$buttonedit = "<a href='https://yogibook.yogasoul.it/' target='_blank' class='v-button v-font-size' style='box-sizing: border-box;display: inline-block;text-decoration: none;-webkit-text-size-adjust: none;text-align: center;color: #FFFFFF; background-color: #3AAEE0; border-radius: 4px;-webkit-border-radius: 4px; -moz-border-radius: 4px; width:auto; max-width:100%; overflow-wrap: break-word; word-break: break-word; word-wrap:break-word; mso-border-alt: none;font-size: 14px;'>
|
|
||||||
<span style='display:block;padding:10px 20px;line-height:120%;'><span style='line-height: 16.8px;'>YogiBook - YogaSoul</span></span>
|
|
||||||
</a>";
|
|
||||||
|
|
||||||
$mail = new PHPMailer(true);
|
|
||||||
try {
|
|
||||||
$mail->isSMTP();
|
|
||||||
$mail->Host = $_ENV['MAIL_HOST'];
|
|
||||||
$mail->SMTPAuth = true;
|
|
||||||
$mail->Username = $_ENV['MAIL_USERNAME'];
|
|
||||||
$mail->Password = $_ENV['MAIL_PASSWORD'];
|
|
||||||
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'];
|
|
||||||
$mail->Port = (int) $_ENV['MAIL_PORT'];
|
|
||||||
|
|
||||||
if (!file_exists('mail/emailtemplate2.php')) {
|
|
||||||
throw new Exception("File emailtemplate2.php non trovato.");
|
|
||||||
}
|
}
|
||||||
include('mail/emailtemplate2.php');
|
SchoolMail::toStudent((string) $bk['email'], (string) $bk['first_name'], 'Lezione cancellata', $lines, '', $school, true);
|
||||||
|
|
||||||
if (!isset($mailmessage1)) {
|
|
||||||
throw new Exception("Variabile \$mailmessage1 non definita in emailtemplate2.php.");
|
|
||||||
}
|
|
||||||
|
|
||||||
$htmlContent = str_replace('{message}', $messagecancel, $mailmessage1);
|
|
||||||
|
|
||||||
$mail->From = $_ENV['MAIL_FROM_ADDRESS'];
|
|
||||||
$mail->FromName = $_ENV['MAIL_FROM_NAME'];
|
|
||||||
$mail->addAddress($emailuser);
|
|
||||||
$mail->Subject = "YogiBook - Lezione cancellata con successo!";
|
|
||||||
$mail->Body = $htmlContent;
|
|
||||||
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
|
|
||||||
|
|
||||||
$mail->send();
|
|
||||||
$logMessage .= "Cancellazione confermata per ID $idbookingclass ($newtimeformat), email inviata a $emailuser\n";
|
|
||||||
|
|
||||||
echo "<h1>Cancellazione confermata</h1>";
|
|
||||||
echo "<p>La lezione del $newtimeformat è stata cancellata con successo.</p>";
|
|
||||||
echo "<p>Ricordati di riprenotare entro la scadenza del tuo abbonamento ($expireon).</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$logMessage .= "Cancellazione confermata per ID $idbookingclass ($newtimeformat), ma errore invio email a $emailuser: " . $mail->ErrorInfo . "\n";
|
|
||||||
echo "<h1>Cancellazione confermata</h1>";
|
|
||||||
echo "<p>La lezione del $newtimeformat è stata cancellata con successo, ma non è stato possibile inviare l'email di conferma.</p>";
|
|
||||||
echo "<p>Ricordati di riprenotare entro la scadenza del tuo abbonamento ($expireon).</p>";
|
|
||||||
echo "<a href='https://yogibook.yogasoul.it'>Torna al portale</a>";
|
|
||||||
}
|
}
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
$state = 'done';
|
||||||
$updateStmt->close();
|
|
||||||
$stmt->close();
|
|
||||||
$conn->close();
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$logMessage .= "Accesso a modale per ID $idbookingclass, token: $token, opzione riprogrammazione: rebook-from-cancel.php?idbookingclass=$idbookingclass&token=" . urlencode($token) . "\n";
|
$when = $bk ? date('d-m-Y H:i', strtotime($bk['dateschedule'])) : '';
|
||||||
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
$expiry = ($bk && !empty($bk['expireon'])) ? date('d-m-Y', strtotime($bk['expireon'])) : null;
|
||||||
|
$schName = $school['name'] ?? 'YogiBook';
|
||||||
|
$baseQs = 'idbookingclass=' . $id . '&token=' . urlencode($token);
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="it">
|
<html lang="it">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>YogiBook - Cancellazione Lezione</title>
|
<title><?php echo e($schName); ?> - Gestione lezione</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
|
||||||
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
|
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
background: #f5f6f8;
|
||||||
text-align: center;
|
font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
||||||
padding: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.box {
|
||||||
max-width: 600px;
|
max-width: 520px;
|
||||||
margin: 0 auto;
|
margin: 60px auto;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 6px 26px rgba(0, 0, 0, .08);
|
||||||
|
padding: 32px 28px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box h1 {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1f2937;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.school {
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 13px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .05em;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 14px;
|
||||||
|
margin: 18px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson strong {
|
||||||
|
display: block;
|
||||||
|
font-size: 17px;
|
||||||
|
color: #1f2937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 40px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="box">
|
||||||
<h1>Gestione Lezione</h1>
|
<div class="school"><?php echo e($schName); ?></div>
|
||||||
<p>Lezione: <?php echo htmlspecialchars($servicename); ?> del <?php echo htmlspecialchars($newtimeformat); ?></p>
|
|
||||||
|
<?php if ($state === 'invalid') : ?>
|
||||||
|
<div class="icon" style="color:#e67e22;"><i class="fas fa-link-slash"></i></div>
|
||||||
|
<h1>Link non valido</h1>
|
||||||
|
<p class="text-muted">Il link non è valido oppure la lezione è già stata cancellata o spostata.</p>
|
||||||
|
|
||||||
|
<?php elseif ($state === 'toolate') : ?>
|
||||||
|
<div class="icon" style="color:#c0392b;"><i class="fas fa-clock"></i></div>
|
||||||
|
<h1>Cancellazione non più possibile</h1>
|
||||||
|
<div class="lesson"><strong><?php echo e($bk['servicename']); ?></strong><?php echo e($when); ?></div>
|
||||||
|
<p class="text-muted">Il termine per cancellare o spostare questa lezione è scaduto.</p>
|
||||||
|
|
||||||
|
<?php elseif ($state === 'done') : ?>
|
||||||
|
<div class="icon" style="color:#1ebf73;"><i class="fas fa-circle-check"></i></div>
|
||||||
|
<h1>Lezione cancellata</h1>
|
||||||
|
<div class="lesson"><strong><?php echo e($bk['servicename']); ?></strong><?php echo e($when); ?></div>
|
||||||
|
<?php if ($expiry) : ?>
|
||||||
|
<p>Ricordati di riprenotarla entro il <strong><?php echo e($expiry); ?></strong>.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="icon" style="color:#2980b9;"><i class="fas fa-calendar-day"></i></div>
|
||||||
|
<h1>Cosa vuoi fare con questa lezione?</h1>
|
||||||
|
<div class="lesson"><strong><?php echo e($bk['servicename']); ?></strong><?php echo e($when); ?></div>
|
||||||
|
<?php if ($expiry) : ?>
|
||||||
|
<p class="text-muted" style="font-size:14px;">Pacchetto valido fino al <?php echo e($expiry); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="d-flex gap-2 justify-content-center flex-wrap mt-3">
|
||||||
|
<a href="rebook-from-cancel.php?<?php echo e($baseQs); ?>" class="btn btn-primary"><i class="fas fa-calendar-alt me-1"></i> Sposta la lezione</a>
|
||||||
|
<button type="button" class="btn btn-outline-danger" id="btn-cancel"><i class="fas fa-trash me-1"></i> Cancella la lezione</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="mt-4"><a href="userpanel.php"><i class="fas fa-arrow-left me-1"></i> Vai alle tue lezioni</a></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($state === 'ask') : ?>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.getElementById('btn-cancel').addEventListener('click', function() {
|
||||||
console.log("Modale SweetAlert2 avviato per ID <?php echo $idbookingclass; ?>, token: <?php echo urlencode($token); ?>");
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Cosa vuoi fare?",
|
title: 'Cancellare la lezione?',
|
||||||
html: "Puoi cancellare la lezione del <?php echo htmlspecialchars($newtimeformat); ?> o riprogrammarla.<br>Scadenza abbonamento: <?php echo htmlspecialchars($expireon); ?><br><br><strong>Debug:</strong> Reindirizzamento previsto: rebook-from-cancel.php?idbookingclass=<?php echo $idbookingclass; ?>&token=<?php echo urlencode($token); ?>",
|
html: <?php echo json_encode($expiry ? 'Ricordati di riprenotarla entro il <strong>' . $expiry . '</strong>.' : 'Potrai riprenotarla dal tuo pannello.'); ?>,
|
||||||
icon: "question",
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: "#d33",
|
confirmButtonColor: '#d33',
|
||||||
cancelButtonColor: "#3085d6",
|
confirmButtonText: 'Sì, cancella',
|
||||||
confirmButtonText: "Cancella Lezione",
|
cancelButtonText: 'Annulla'
|
||||||
cancelButtonText: "Riprogramma Lezione",
|
}).then(function(r) {
|
||||||
showDenyButton: true,
|
if (r.isConfirmed) window.location.replace('cancella-prenotazione.php?<?php echo $baseQs; ?>&action=cancel');
|
||||||
denyButtonText: "Riprogramma Lezione",
|
|
||||||
denyButtonColor: "#e47c06ff"
|
|
||||||
}).then((result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
console.log("Cliccato 'Cancella Lezione' per ID <?php echo $idbookingclass; ?>");
|
|
||||||
Swal.fire({
|
|
||||||
title: "Attenzione!",
|
|
||||||
text: "La lezione sarà cancellata. Ricordati di riprenotare entro la scadenza del tuo abbonamento (<?php echo htmlspecialchars($expireon); ?>)!",
|
|
||||||
icon: "warning",
|
|
||||||
confirmButtonText: "Conferma Cancellazione",
|
|
||||||
showCancelButton: true,
|
|
||||||
cancelButtonText: "Annulla"
|
|
||||||
}).then((confirmResult) => {
|
|
||||||
if (confirmResult.isConfirmed) {
|
|
||||||
console.log("Conferma cancellazione, reindirizzamento a: ?idbookingclass=<?php echo $idbookingclass; ?>&token=<?php echo urlencode($token); ?>&action=cancel");
|
|
||||||
window.location.replace("?idbookingclass=<?php echo $idbookingclass; ?>&token=<?php echo urlencode($token); ?>&action=cancel");
|
|
||||||
} else {
|
|
||||||
console.log("Cancellazione annullata");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (result.isCancel) {
|
|
||||||
console.log("Cliccato 'Riprogramma Lezione' per ID <?php echo $idbookingclass; ?>, reindirizzamento a: rebook-from-cancel.php?idbookingclass=<?php echo $idbookingclass; ?>&token=<?php echo urlencode($token); ?>");
|
|
||||||
try {
|
|
||||||
window.location.replace("rebook-from-cancel.php?idbookingclass=<?php echo $idbookingclass; ?>&token=<?php echo urlencode($token); ?>");
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Errore durante il reindirizzamento: ", e);
|
|
||||||
alert("Errore: impossibile reindirizzare a rebook-from-cancel.php. Controlla la console del browser.");
|
|
||||||
}
|
|
||||||
} else if (result.isDenied) {
|
|
||||||
console.log("Cliccato 'Riprogramma Lezione', reindirizzamento a: https://yogibook.yogasoul.it");
|
|
||||||
window.location.replace("rebook-from-cancel.php?idbookingclass=<?php echo $idbookingclass; ?>&token=<?php echo urlencode($token); ?>");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</div>
|
<?php endif; ?>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
<?php
|
|
||||||
$stmt->close();
|
|
||||||
// Connessione $bkngstm gestita globalmente: non la chiudiamo qui
|
|
||||||
?>
|
|
||||||
@@ -1,36 +1,60 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elimina una propagazione della scuola corrente: le sue lezioni
|
||||||
|
* e le prenotazioni collegate. Se ci sono prenotazioni chiede conferma.
|
||||||
|
*/
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
$token = $_GET['token'] ?? '';
|
$token = preg_replace('/[^a-f0-9]/i', '', (string) ($_GET['token'] ?? ''));
|
||||||
$confirm = ($_GET['confirm'] ?? '') === 'Y';
|
$confirm = ($_GET['confirm'] ?? '') === 'Y';
|
||||||
|
|
||||||
if ($token === '') {
|
$st = $pdo->prepare("SELECT idpropagation FROM propagation WHERE token = ? AND idschool = ?");
|
||||||
header('Location: admin-services.php');
|
$st->execute([$token, $idschool]);
|
||||||
|
if ($token === '' || !$st->fetchColumn()) {
|
||||||
|
header('Location: admin-services.php?message=notfound');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conta le prenotazioni utente collegate alle lezioni di questa propagazione
|
$st = $pdo->prepare(
|
||||||
$stmt = $pdo->prepare(
|
|
||||||
"SELECT COUNT(*) FROM bookingclass b
|
"SELECT COUNT(*) FROM bookingclass b
|
||||||
JOIN serviceschedule s ON b.idserviceschedule = s.idserviceschedule
|
JOIN serviceschedule s ON b.idserviceschedule = s.idserviceschedule
|
||||||
WHERE s.propagation_token = :token"
|
WHERE s.propagation_token = ? AND s.idschool = ?"
|
||||||
);
|
);
|
||||||
$stmt->execute([':token' => $token]);
|
$st->execute([$token, $idschool]);
|
||||||
$prenotazioni = (int) $stmt->fetchColumn();
|
$prenotazioni = (int) $st->fetchColumn();
|
||||||
|
|
||||||
// Se ci sono prenotazioni e non è ancora arrivata la conferma esplicita -> chiedi
|
|
||||||
if ($prenotazioni > 0 && !$confirm) {
|
if ($prenotazioni > 0 && !$confirm) {
|
||||||
header('Location: admin-services.php?message=confirmdelete&token=' . urlencode($token) . '&count=' . $prenotazioni);
|
header('Location: admin-services.php?message=confirmdelete&token=' . urlencode($token) . '&count=' . $prenotazioni);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Procedi con la cancellazione
|
try {
|
||||||
$stmt = $pdo->prepare("DELETE FROM serviceschedule WHERE propagation_token = :token");
|
$pdo->beginTransaction();
|
||||||
$stmt->execute([':token' => $token]);
|
|
||||||
|
|
||||||
$stmt = $pdo->prepare("DELETE FROM propagation WHERE token = :token");
|
// 1) Prenotazioni delle lezioni di questa propagazione (non c'è FK: vanno tolte a mano)
|
||||||
$stmt->execute([':token' => $token]);
|
$pdo->prepare(
|
||||||
|
"DELETE b FROM bookingclass b
|
||||||
|
JOIN serviceschedule s ON b.idserviceschedule = s.idserviceschedule
|
||||||
|
WHERE s.propagation_token = ? AND s.idschool = ?"
|
||||||
|
)->execute([$token, $idschool]);
|
||||||
|
|
||||||
header('Location: admin-services.php?message=propdeleted');
|
// 2) Lezioni
|
||||||
exit;
|
$pdo->prepare("DELETE FROM serviceschedule WHERE propagation_token = ? AND idschool = ?")->execute([$token, $idschool]);
|
||||||
|
|
||||||
|
// 3) Propagazione
|
||||||
|
$pdo->prepare("DELETE FROM propagation WHERE token = ? AND idschool = ?")->execute([$token, $idschool]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
header('Location: admin-services.php?message=propdeleted');
|
||||||
|
exit;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
error_log('cancelpropagation error: ' . $ex->getMessage());
|
||||||
|
header('Location: admin-services.php?message=error');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,34 +1,50 @@
|
|||||||
<?php require_once('include/headscript.php'); ?>
|
|
||||||
<?php // require_once('Connections/bkngstm.php'); ?>
|
|
||||||
<?php // require_once('webassist/mysqli/rsobj.php'); ?>
|
|
||||||
<?php // require_once('webassist/mysqli/queryobj.php'); ?>
|
|
||||||
<?php
|
<?php
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
// Controlla la connessione
|
/**
|
||||||
if ($conn->connect_error) {
|
* Elimina una classe (service) della scuola corrente.
|
||||||
die("Connessione fallita: " . $conn->connect_error);
|
* Bloccato se esistono lezioni in calendario o ordini collegati
|
||||||
|
* (serve a non perdere storico e prenotazioni).
|
||||||
|
*/
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
|
$idservice = (int) ($_GET['idservice'] ?? 0);
|
||||||
|
|
||||||
|
if (!SchoolScope::belongs('service', $idservice)) {
|
||||||
|
header('Location: admin-services.php?message=notfound');
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifica che sia stato passato il parametro "idservice" tramite GET
|
try {
|
||||||
if(isset($_GET['idservice'])) {
|
$chk = $pdo->prepare(
|
||||||
// Escapa e sanifica il valore dell'idservice per prevenire SQL injection
|
"SELECT
|
||||||
$idservice = $conn->real_escape_string($_GET['idservice']);
|
(SELECT COUNT(*) FROM serviceschedule WHERE idservice = :s1 AND idschool = :sc1) +
|
||||||
|
(SELECT COUNT(*) FROM orderbook WHERE idservice = :s2 AND idschool = :sc2)"
|
||||||
// Costruisci la query di cancellazione
|
);
|
||||||
$delete_query = "DELETE FROM service WHERE idservice = '$idservice'";
|
$chk->execute([':s1' => $idservice, ':sc1' => $idschool, ':s2' => $idservice, ':sc2' => $idschool]);
|
||||||
|
if ((int) $chk->fetchColumn() > 0) {
|
||||||
// Esegui la query di cancellazione
|
header('Location: admin-services.php?message=hasdata');
|
||||||
if ($conn->query($delete_query) === TRUE) {
|
exit;
|
||||||
// Reindirizza alla pagina admin-service.php dopo la cancellazione
|
|
||||||
header("Location: admin-services.php");
|
|
||||||
exit();
|
|
||||||
} else {
|
|
||||||
echo "Errore nella cancellazione del record: " . $conn->error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
// Associazioni in cui compare la classe (come principale o associata)
|
||||||
|
$pdo->prepare(
|
||||||
|
"DELETE FROM associateclass
|
||||||
|
WHERE idschool = ? AND (idmainservice = ? OR idassociateservice = ?)"
|
||||||
|
)->execute([$idschool, $idservice, $idservice]);
|
||||||
|
$pdo->prepare("DELETE FROM propagation WHERE idservice = ? AND idschool = ?")->execute([$idservice, $idschool]);
|
||||||
|
$pdo->prepare("DELETE FROM service WHERE idservice = ? AND idschool = ?")->execute([$idservice, $idschool]);
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
header('Location: admin-services.php?message=deleted');
|
||||||
|
exit;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
error_log('cancelservice error: ' . $ex->getMessage());
|
||||||
|
header('Location: admin-services.php?message=notfound');
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chiudi la connessione al database
|
|
||||||
$conn->close();
|
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -1,34 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
include('Connections/bkngstm.php');
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
/**
|
||||||
|
* Elimina un ordine PENDING della scuola corrente (mai propagato, senza prenotazioni).
|
||||||
|
* GET: idorder.
|
||||||
|
*/
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
if ($conn->connect_error) {
|
$idorder = (int) ($_GET['idorder'] ?? 0);
|
||||||
die("Connessione fallita: " . $conn->connect_error);
|
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT ob.idorderbook,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b WHERE b.idorder = ob.idorderbook) AS nbookings
|
||||||
|
FROM orderbook ob
|
||||||
|
WHERE ob.idorderbook = ? AND ob.idschool = ? AND ob.status = 'pending'"
|
||||||
|
);
|
||||||
|
$st->execute([$idorder, $idschool]);
|
||||||
|
$row = $st->fetch();
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
header('Location: orderbooklist.php?msg=notfound');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ((int) $row['nbookings'] > 0) {
|
||||||
|
header('Location: orderbooklist.php?msg=hasbookings');
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancellazione del record
|
$pdo->prepare("DELETE FROM orderbook WHERE idorderbook = ? AND idschool = ? AND status = 'pending'")
|
||||||
if (isset($_GET['idorder'])) {
|
->execute([$idorder, $idschool]);
|
||||||
$idorder = $_GET['idorder'];
|
|
||||||
|
|
||||||
// Utilizzo di prepared statement per evitare SQL injection
|
header('Location: orderbooklist.php?msg=deleted');
|
||||||
$stmt = $conn->prepare("DELETE FROM orderbook WHERE idorderbook = ?");
|
exit;
|
||||||
$stmt->bind_param("i", $idorder);
|
|
||||||
|
|
||||||
if ($stmt->execute()) {
|
|
||||||
echo "Ordine cancellato con successo!";
|
|
||||||
} else {
|
|
||||||
echo "Errore nella cancellazione: " . $conn->error;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt->close();
|
|
||||||
// Reindirizzamento alla pagina orderbooklist.php
|
|
||||||
header("Location: orderbooklist.php");
|
|
||||||
exit();
|
|
||||||
} else {
|
|
||||||
echo "ID ordine non valido.";
|
|
||||||
// Potresti voler aggiungere un reindirizzamento anche qui, se desideri
|
|
||||||
}
|
|
||||||
|
|
||||||
$conn->close();
|
|
||||||
?>
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
require_once('include/headscript.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visualizza/scarica un certificato in modo protetto.
|
||||||
|
* GET: id = idcertificateuserprofile.
|
||||||
|
* Consentito a: proprietaria del certificato, staff della scuola del certificato.
|
||||||
|
*/
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
$id = (int) ($_GET['id'] ?? 0);
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT * FROM certificateuserprofile WHERE idcertificateuserprofile = ? AND idschool = ?");
|
||||||
|
$st->execute([$id, $idschool]);
|
||||||
|
$cert = $st->fetch();
|
||||||
|
|
||||||
|
$allowed = $cert && ((int) $cert['iduser'] === (int) $iduserlogin || SchoolContext::isStaff());
|
||||||
|
if (!$allowed) {
|
||||||
|
http_response_code(404);
|
||||||
|
exit('Documento non trovato.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Percorsi possibili: archivio privato (futuro) e cartella storica pubblica
|
||||||
|
$name = basename((string) $cert['filenamedocument']);
|
||||||
|
$candidates = [
|
||||||
|
dirname(__DIR__) . '/storage/app/certificates/' . (int) $cert['idschool'] . '/' . $name,
|
||||||
|
__DIR__ . '/user/document/' . $name,
|
||||||
|
];
|
||||||
|
$path = null;
|
||||||
|
foreach ($candidates as $c) {
|
||||||
|
if (is_file($c)) {
|
||||||
|
$path = $c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$path) {
|
||||||
|
http_response_code(404);
|
||||||
|
exit('File non disponibile.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$mime = (new finfo(FILEINFO_MIME_TYPE))->file($path);
|
||||||
|
if (!in_array($mime, ['application/pdf', 'image/jpeg', 'image/png'], true)) {
|
||||||
|
http_response_code(415);
|
||||||
|
exit('Formato non supportato.');
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Content-Type: ' . $mime);
|
||||||
|
header('Content-Length: ' . filesize($path));
|
||||||
|
header('Content-Disposition: inline; filename="certificato-' . $id . '.' . pathinfo($name, PATHINFO_EXTENSION) . '"');
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
header('Cache-Control: private, no-store');
|
||||||
|
readfile($path);
|
||||||
|
exit;
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once('include/headscript.php');
|
require_once('include/headscript.php');
|
||||||
|
SchoolContext::requireSchoolAdmin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vista admin di tutti i certificati caricati dagli utenti,
|
* Vista admin dei certificati caricati dagli allievi della scuola corrente,
|
||||||
* con DataTables per ricerca e ordinamento.
|
* con DataTables per ricerca e ordinamento.
|
||||||
|
* I file si aprono tramite certificate.php (controllo permessi), mai con link diretto.
|
||||||
*/
|
*/
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
@@ -26,14 +28,18 @@ function avatarColor(string $seed): string
|
|||||||
|
|
||||||
$message = $_GET['message'] ?? 'n';
|
$message = $_GET['message'] ?? 'n';
|
||||||
|
|
||||||
// Elenco certificati con dati utente
|
// Certificati della scuola con dati utente
|
||||||
$sql = "SELECT certificateuserprofile.*, auth_users.first_name, auth_users.last_name
|
$st = $pdo->prepare(
|
||||||
FROM certificateuserprofile
|
"SELECT c.*, u.first_name, u.last_name
|
||||||
LEFT JOIN auth_users ON certificateuserprofile.iduser = auth_users.id
|
FROM certificateuserprofile c
|
||||||
ORDER BY auth_users.last_name, auth_users.first_name";
|
LEFT JOIN auth_users u ON c.iduser = u.id
|
||||||
$documents = $pdo->query($sql)->fetchAll();
|
WHERE c.idschool = ?
|
||||||
|
ORDER BY u.last_name, u.first_name"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$documents = $st->fetchAll();
|
||||||
|
|
||||||
// Determina se un certificato è scaduto (per evidenziarlo)
|
// Per evidenziare i certificati scaduti
|
||||||
$today = date('Y-m-d');
|
$today = date('Y-m-d');
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
@@ -43,8 +49,7 @@ $today = date('Y-m-d');
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>YogiBook - Certificati (admin)</title>
|
<title>YogiBook - Certificati (admin)</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta content="YogiBook - Prenotazione facile YogaSoul" name="description" />
|
<meta content="YogiBook" name="description" />
|
||||||
<meta content="Advanced Creative Solutions" name="author" />
|
|
||||||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||||||
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
<link href="assets/css/bootstrap.min.css" id="bootstrap-style" rel="stylesheet" type="text/css" />
|
||||||
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
<link href="assets/css/icons.min.css" rel="stylesheet" type="text/css" />
|
||||||
@@ -195,7 +200,7 @@ $today = date('Y-m-d');
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<?php include('include/languageselection.php'); ?>
|
<?php include('include/schoolswitcher.php'); ?><?php include('include/languageselection.php'); ?>
|
||||||
<?php include('include/profiletopbar.php'); ?>
|
<?php include('include/profiletopbar.php'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -262,7 +267,7 @@ $today = date('Y-m-d');
|
|||||||
</td>
|
</td>
|
||||||
<td><?php echo e($d['uploaded_at'] ?? 'N/D'); ?></td>
|
<td><?php echo e($d['uploaded_at'] ?? 'N/D'); ?></td>
|
||||||
<td>
|
<td>
|
||||||
<a class="doc-link" href="user/document/<?php echo e(rawurlencode($d['filenamedocument'])); ?>" target="_blank" rel="noopener">
|
<a class="doc-link" href="certificate.php?id=<?php echo $idc; ?>" target="_blank" rel="noopener">
|
||||||
<i class="fas fa-file-arrow-down"></i> Apri
|
<i class="fas fa-file-arrow-down"></i> Apri
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BookingRules
|
||||||
|
* Regole di prenotazione in un unico posto, sempre limitate alla scuola corrente.
|
||||||
|
* Usata da: selectorder, bookingpanel, bookingpanelorder, bookandgo, rebookandgo,
|
||||||
|
* delete_lesson e (in seguito) dalle API dell'app.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class BookingRules
|
||||||
|
{
|
||||||
|
/* ================================================================== */
|
||||||
|
/* ORDINI / TICKET */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
/** Ordine dell'utente nella scuola corrente, con nome servizio (null se non suo) */
|
||||||
|
public static function order(int $idorder, int $userId): ?array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT ob.*, s.servicename
|
||||||
|
FROM orderbook ob
|
||||||
|
LEFT JOIN service s ON s.idservice = ob.idservice
|
||||||
|
WHERE ob.idorderbook = ? AND ob.iduser = ? AND ob.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idorder, $userId, SchoolContext::id()]);
|
||||||
|
return $st->fetch() ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tutti gli ordini dell'utente nella scuola corrente */
|
||||||
|
public static function userOrders(int $userId): array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT ob.*, s.servicename
|
||||||
|
FROM orderbook ob
|
||||||
|
LEFT JOIN service s ON s.idservice = ob.idservice
|
||||||
|
WHERE ob.iduser = ? AND ob.idschool = ?
|
||||||
|
ORDER BY ob.order_date_created DESC, ob.idorderbook DESC"
|
||||||
|
);
|
||||||
|
$st->execute([$userId, SchoolContext::id()]);
|
||||||
|
return $st->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ticket totali dell'ordine: nticket, o quantityclass se nticket è vuoto */
|
||||||
|
public static function ticketsOf(array $order): int
|
||||||
|
{
|
||||||
|
$n = (int) ($order['nticket'] ?? 0);
|
||||||
|
return $n > 0 ? $n : (int) ($order['quantityclass'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ticket usati: prenotazioni non annullate e non omaggio collegate all'ordine */
|
||||||
|
public static function usedTickets(int $idorder): int
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT COUNT(*) FROM bookingclass
|
||||||
|
WHERE idorder = ? AND idschool = ?
|
||||||
|
AND status <> 'cancelled' AND is_gift = 'N'"
|
||||||
|
);
|
||||||
|
$st->execute([$idorder, SchoolContext::id()]);
|
||||||
|
return (int) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function remaining(array $order): int
|
||||||
|
{
|
||||||
|
return max(0, self::ticketsOf($order) - self::usedTickets((int) $order['idorderbook']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isExpired(array $order): bool
|
||||||
|
{
|
||||||
|
return !empty($order['expireon']) && $order['expireon'] < date('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Si può ancora riprogrammare con questo ordine? (gli omaggi, senza ordine, no) */
|
||||||
|
public static function canReprogram(?array $order): bool
|
||||||
|
{
|
||||||
|
if (!$order) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (int) ($order['reprogrammed'] ?? 0) < (int) ($order['maxreschedule'] ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* CLASSI / POSTI */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
/** Servizi prenotabili con un ordine: il servizio + le classi associate */
|
||||||
|
public static function allowedServices(int $idservice): array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT idassociateservice FROM associateclass WHERE idmainservice = ? AND idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idservice, SchoolContext::id()]);
|
||||||
|
$ids = array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN));
|
||||||
|
array_unshift($ids, $idservice);
|
||||||
|
return array_values(array_unique($ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Lezione in calendario della scuola corrente, con dati del servizio */
|
||||||
|
public static function schedule(int $idschedule): ?array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT ss.*, s.servicename, s.maxcapacity, s.colorclass, s.idteacher
|
||||||
|
FROM serviceschedule ss
|
||||||
|
JOIN service s ON s.idservice = ss.idservice
|
||||||
|
WHERE ss.idserviceschedule = ? AND ss.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idschedule, SchoolContext::id()]);
|
||||||
|
return $st->fetch() ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Posti occupati (prenotate + in attesa di conferma) */
|
||||||
|
public static function occupied(int $idschedule): int
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT COUNT(*) FROM bookingclass
|
||||||
|
WHERE idserviceschedule = ? AND idschool = ? AND status IN ('booked','pending')"
|
||||||
|
);
|
||||||
|
$st->execute([$idschedule, SchoolContext::id()]);
|
||||||
|
return (int) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** L'utente ha già una prenotazione attiva (anche in coda) in questa lezione? */
|
||||||
|
public static function userHasBooking(int $idschedule, int $userId): bool
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT 1 FROM bookingclass
|
||||||
|
WHERE idserviceschedule = ? AND iduser = ? AND idschool = ? AND status <> 'cancelled'
|
||||||
|
LIMIT 1"
|
||||||
|
);
|
||||||
|
$st->execute([$idschedule, $userId, SchoolContext::id()]);
|
||||||
|
return (bool) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function waitingListEnabled(): bool
|
||||||
|
{
|
||||||
|
return SchoolSettings::get('waitinglist_enabled', 'N') === 'Y';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stato di una nuova prenotazione da parte dell'allievo:
|
||||||
|
* 'pending' c'è posto (lo staff conferma)
|
||||||
|
* 'waiting' classe piena, lista d'attesa attiva
|
||||||
|
* 'full' classe piena, lista d'attesa disattivata
|
||||||
|
*/
|
||||||
|
public static function decideStatus(array $schedule): string
|
||||||
|
{
|
||||||
|
$max = (int) ($schedule['maxcapacity'] ?? 0);
|
||||||
|
if ($max <= 0 || self::occupied((int) $schedule['idserviceschedule']) < $max) {
|
||||||
|
return 'pending';
|
||||||
|
}
|
||||||
|
return self::waitingListEnabled() ? 'waiting' : 'full';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* CANCELLAZIONE */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* L'allievo può ancora cancellare/riprogrammare la lezione?
|
||||||
|
* Regola attuale (Seregno), da rendere configurabile per scuola:
|
||||||
|
* - lezione passata: no
|
||||||
|
* - lezione in un altro giorno: sì
|
||||||
|
* - lezione di oggi entro le 17:00: entro le 00:01 di oggi
|
||||||
|
* - lezione di oggi dopo le 17:00: entro le 12:00 di oggi
|
||||||
|
*/
|
||||||
|
public static function canCancel(string $dateschedule): bool
|
||||||
|
{
|
||||||
|
$now = new DateTime();
|
||||||
|
$class = new DateTime($dateschedule);
|
||||||
|
|
||||||
|
if ($class <= $now) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($class->format('Y-m-d') !== $now->format('Y-m-d')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$h = (int) $class->format('H');
|
||||||
|
$m = (int) $class->format('i');
|
||||||
|
$before1700 = $h < 17 || ($h === 17 && $m === 0);
|
||||||
|
$deadline = new DateTime($class->format('Y-m-d') . ($before1700 ? ' 00:01:00' : ' 12:00:00'));
|
||||||
|
return $now <= $deadline;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OrderRules
|
||||||
|
* Regole sugli ordini (orderbook) della scuola corrente:
|
||||||
|
* scadenza, riprogrammazioni consentite, collegamento/creazione utente.
|
||||||
|
* Usata da propagatesingleorder, calculate_expiry, inserisci_ordine e
|
||||||
|
* (in seguito) dagli ordini in arrivo da WooCommerce / Stripe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class OrderRules
|
||||||
|
{
|
||||||
|
/** Ordine della scuola corrente (qualsiasi utente), con nome servizio */
|
||||||
|
public static function find(int $idorder): ?array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT ob.*, s.servicename
|
||||||
|
FROM orderbook ob
|
||||||
|
LEFT JOIN service s ON s.idservice = ob.idservice
|
||||||
|
WHERE ob.idorderbook = ? AND ob.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idorder, SchoolContext::id()]);
|
||||||
|
return $st->fetch() ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parametri di scadenza (expiryparameter) della scuola per un numero di lezioni */
|
||||||
|
public static function expiryParams(int $quantityclass): ?array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT * FROM expiryparameter WHERE quantityclass = ? AND idschool = ? LIMIT 1"
|
||||||
|
);
|
||||||
|
$st->execute([$quantityclass, SchoolContext::id()]);
|
||||||
|
return $st->fetch() ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scadenza proposta (Y-m-d): data della N-esima lezione del servizio a partire
|
||||||
|
* dalla prima lezione, con N = expirylessons dei parametri della scuola.
|
||||||
|
* Null se non calcolabile (parametri mancanti o calendario insufficiente).
|
||||||
|
*/
|
||||||
|
public static function calculateExpiry(array $order): ?string
|
||||||
|
{
|
||||||
|
$params = self::expiryParams((int) $order['quantityclass']);
|
||||||
|
$n = (int) ($params['expirylessons'] ?? 0);
|
||||||
|
if ($n <= 0 || empty($order['idservice'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$from = $order['first_lesson_date'] ?: date('Y-m-d');
|
||||||
|
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT dateschedule FROM serviceschedule
|
||||||
|
WHERE idservice = ? AND idschool = ? AND dateschedule >= ?
|
||||||
|
ORDER BY dateschedule
|
||||||
|
LIMIT 1 OFFSET " . ($n - 1)
|
||||||
|
);
|
||||||
|
$st->execute([(int) $order['idservice'], SchoolContext::id(), $from]);
|
||||||
|
$date = $st->fetchColumn();
|
||||||
|
return $date ? substr((string) $date, 0, 10) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Riprogrammazioni consentite per un numero di lezioni (null se non configurato) */
|
||||||
|
public static function maxReschedule(int $quantityclass): ?int
|
||||||
|
{
|
||||||
|
$params = self::expiryParams($quantityclass);
|
||||||
|
return $params ? (int) $params['reschedulenumber'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordine "a ingressi liberi" (OpenFlexy): niente lezioni assegnate in automatico,
|
||||||
|
* l'allievo prenota da sé. Flag dell'ordine o, per compatibilità, nome servizio.
|
||||||
|
*/
|
||||||
|
public static function isFlexible(array $order): bool
|
||||||
|
{
|
||||||
|
return ($order['is_openflexy'] ?? 'N') === 'Y'
|
||||||
|
|| strcasecmp(trim((string) ($order['servicename'] ?? '')), 'OpenFlexy') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trova l'utente per email o lo crea (password casuale: l'allievo la imposta
|
||||||
|
* con "password dimenticata"). In entrambi i casi lo iscrive alla scuola corrente.
|
||||||
|
* @return array{0:int,1:bool} [id utente, creato ora]
|
||||||
|
*/
|
||||||
|
public static function resolveUser(string $email, string $firstName, string $lastName): array
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$email = trim($email);
|
||||||
|
$created = false;
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT id FROM auth_users WHERE email = ? LIMIT 1");
|
||||||
|
$st->execute([$email]);
|
||||||
|
$userId = (int) $st->fetchColumn();
|
||||||
|
|
||||||
|
if ($userId === 0) {
|
||||||
|
$pdo->prepare(
|
||||||
|
"INSERT INTO auth_users (email, password, first_name, last_name, role_id, status, created_at, avatar)
|
||||||
|
VALUES (?, ?, ?, ?, 2, 'Active', NOW(), 'meditationb.png')"
|
||||||
|
)->execute([
|
||||||
|
$email,
|
||||||
|
password_hash(bin2hex(random_bytes(16)), PASSWORD_BCRYPT),
|
||||||
|
$firstName,
|
||||||
|
$lastName,
|
||||||
|
]);
|
||||||
|
$userId = (int) $pdo->lastInsertId();
|
||||||
|
$created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SchoolScope::addMember($userId, 'student');
|
||||||
|
return [$userId, $created];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,606 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlatformBilling
|
||||||
|
* Abbonamento delle scuole al portale YogiBook.
|
||||||
|
*
|
||||||
|
* - Impostazioni del superadmin (tabella platform_settings, chiave/valore)
|
||||||
|
* - Piani (platform_plans) e stato dell'abbonamento di una scuola
|
||||||
|
* - Ordini di rinnovo (platform_orders): creazione, pagamento, annullo
|
||||||
|
* - Stripe Checkout (chiamate API dirette, senza librerie) e verifica webhook
|
||||||
|
*
|
||||||
|
* Le chiavi Stripe stanno SOLO nel .env:
|
||||||
|
* STRIPE_SECRET_KEY=sk_test_... (o sk_live_...)
|
||||||
|
* STRIPE_WEBHOOK_SECRET=whsec_...
|
||||||
|
* Funziona anche senza sessione (webhook): passare sempre gli ID espliciti.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlatformBilling
|
||||||
|
{
|
||||||
|
/** Impostazioni ammesse e valori predefiniti */
|
||||||
|
const DEFAULTS = [
|
||||||
|
// Dati del fornitore (per ricevute e riepiloghi)
|
||||||
|
'company_name' => '',
|
||||||
|
'company_vat' => '',
|
||||||
|
'company_address' => '',
|
||||||
|
'company_email' => '',
|
||||||
|
// Regole
|
||||||
|
'vat_rate' => '22',
|
||||||
|
'trial_days' => '30',
|
||||||
|
'reminder_days' => '15',
|
||||||
|
'grace_days' => '7',
|
||||||
|
// Carta
|
||||||
|
'card_enabled' => 'N',
|
||||||
|
// Bonifico
|
||||||
|
'bank_enabled' => 'N',
|
||||||
|
'bank_holder' => '',
|
||||||
|
'bank_iban' => '',
|
||||||
|
'bank_name' => '',
|
||||||
|
'bank_reference' => 'Abbonamento YogiBook {ordine} - {scuola}',
|
||||||
|
'bank_due_days' => '7',
|
||||||
|
];
|
||||||
|
|
||||||
|
const CYCLES = ['month' => 'Mensile', 'year' => 'Annuale'];
|
||||||
|
const METHODS = ['stripe' => 'Carta', 'bank' => 'Bonifico', 'manual' => 'Manuale'];
|
||||||
|
const STATUSES = ['pending' => 'In attesa', 'paid' => 'Pagato', 'cancelled' => 'Annullato', 'refunded' => 'Rimborsato'];
|
||||||
|
|
||||||
|
private static $settings = null;
|
||||||
|
private static $env = null;
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* Impostazioni ed env
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
public static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Valore dal .env (o dalle variabili d'ambiente). Stringa vuota se assente. */
|
||||||
|
public static function env(string $key): string
|
||||||
|
{
|
||||||
|
$v = getenv($key);
|
||||||
|
if ($v !== false && $v !== '') {
|
||||||
|
return (string) $v;
|
||||||
|
}
|
||||||
|
if (!empty($_ENV[$key])) {
|
||||||
|
return (string) $_ENV[$key];
|
||||||
|
}
|
||||||
|
if (!empty($_SERVER[$key]) && is_string($_SERVER[$key])) {
|
||||||
|
return (string) $_SERVER[$key];
|
||||||
|
}
|
||||||
|
if (self::$env === null) {
|
||||||
|
self::$env = [];
|
||||||
|
foreach ([dirname(__DIR__, 2) . '/.env', dirname(__DIR__) . '/.env'] as $file) {
|
||||||
|
if (!is_readable($file)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
|
||||||
|
$line = trim($line);
|
||||||
|
if ($line === '' || $line[0] === '#' || strpos($line, '=') === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
[$k, $val] = array_map('trim', explode('=', $line, 2));
|
||||||
|
if (strlen($val) >= 2 && ($val[0] === '"' || $val[0] === "'") && substr($val, -1) === $val[0]) {
|
||||||
|
$val = substr($val, 1, -1);
|
||||||
|
}
|
||||||
|
self::$env[$k] = $val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (string) (self::$env[$key] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function all(): array
|
||||||
|
{
|
||||||
|
if (self::$settings === null) {
|
||||||
|
self::$settings = self::DEFAULTS;
|
||||||
|
$rows = self::pdo()->query("SELECT setting_key, setting_value FROM platform_settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||||
|
foreach ($rows as $k => $v) {
|
||||||
|
if (array_key_exists($k, self::DEFAULTS)) {
|
||||||
|
self::$settings[$k] = (string) $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self::$settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get(string $key, $default = null)
|
||||||
|
{
|
||||||
|
$all = self::all();
|
||||||
|
return $all[$key] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Salva solo le chiavi ammesse */
|
||||||
|
public static function save(array $data): void
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"INSERT INTO platform_settings (setting_key, setting_value) VALUES (?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"
|
||||||
|
);
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
if (array_key_exists($k, self::DEFAULTS)) {
|
||||||
|
$st->execute([$k, $v === null ? null : (string) $v]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self::$settings = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function appUrl(): string
|
||||||
|
{
|
||||||
|
return rtrim(self::env('APP_URL'), '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** IBAN normalizzato se valido (controllo mod 97), altrimenti null */
|
||||||
|
public static function iban(?string $v): ?string
|
||||||
|
{
|
||||||
|
$v = strtoupper(preg_replace('/\s+/', '', (string) $v));
|
||||||
|
if (!preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/', $v)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$num = '';
|
||||||
|
foreach (str_split(substr($v, 4) . substr($v, 0, 4)) as $ch) {
|
||||||
|
$num .= ctype_alpha($ch) ? (string) (ord($ch) - 55) : $ch;
|
||||||
|
}
|
||||||
|
$rest = 0;
|
||||||
|
foreach (str_split($num, 7) as $chunk) {
|
||||||
|
$rest = (int) (($rest . $chunk) % 97);
|
||||||
|
}
|
||||||
|
return $rest === 1 ? $v : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function ibanFormat(?string $v): string
|
||||||
|
{
|
||||||
|
return trim(chunk_split((string) $v, 4, ' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function money($v): string
|
||||||
|
{
|
||||||
|
return number_format((float) $v, 2, ',', '.') . ' €';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* Metodi di pagamento disponibili
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
public static function stripeSecret(): string
|
||||||
|
{
|
||||||
|
return self::env('STRIPE_SECRET_KEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 'test', 'live' oppure '' se la chiave manca */
|
||||||
|
public static function stripeMode(): string
|
||||||
|
{
|
||||||
|
$k = self::stripeSecret();
|
||||||
|
if (strpos($k, 'sk_live_') === 0 || strpos($k, 'rk_live_') === 0) {
|
||||||
|
return 'live';
|
||||||
|
}
|
||||||
|
if (strpos($k, 'sk_test_') === 0 || strpos($k, 'rk_test_') === 0) {
|
||||||
|
return 'test';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cardAvailable(): bool
|
||||||
|
{
|
||||||
|
return self::get('card_enabled') === 'Y' && self::stripeMode() !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function bankAvailable(): bool
|
||||||
|
{
|
||||||
|
return self::get('bank_enabled') === 'Y' && self::get('bank_holder') !== '' && self::iban(self::get('bank_iban')) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* Piani
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
public static function plans(bool $activeOnly = true): array
|
||||||
|
{
|
||||||
|
$sql = "SELECT * FROM platform_plans" . ($activeOnly ? " WHERE active = 'Y'" : "") . " ORDER BY sort_order, name";
|
||||||
|
return self::pdo()->query($sql)->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function plan(int $idplan): ?array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare("SELECT * FROM platform_plans WHERE idplan = ?");
|
||||||
|
$st->execute([$idplan]);
|
||||||
|
return $st->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Prezzo IVA esclusa del piano per il ciclo, null se non previsto */
|
||||||
|
public static function price(array $plan, string $cycle): ?float
|
||||||
|
{
|
||||||
|
$v = $cycle === 'month' ? $plan['price_month'] : $plan['price_year'];
|
||||||
|
return $v === null ? null : (float) $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array [net, vat_rate, vat_amount, total] */
|
||||||
|
public static function quote(float $net): array
|
||||||
|
{
|
||||||
|
$rate = max(0, (float) self::get('vat_rate', 22));
|
||||||
|
$net = round($net, 2);
|
||||||
|
$vat = round($net * $rate / 100, 2);
|
||||||
|
return [$net, $rate, $vat, round($net + $vat, 2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* Stato dell'abbonamento di una scuola
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
public static function school(int $idschool): ?array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT s.*, p.name AS plan_name, p.price_month, p.price_year, p.max_students
|
||||||
|
FROM schools s
|
||||||
|
LEFT JOIN platform_plans p ON p.idplan = s.idplan
|
||||||
|
WHERE s.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
return $st->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function days(string $from, string $to): int
|
||||||
|
{
|
||||||
|
return (int) (new DateTimeImmutable($from))->diff(new DateTimeImmutable($to))->format('%r%a');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stato calcolato.
|
||||||
|
* code: exempt | active | expiring | trial | grace | expired | none
|
||||||
|
* @return array ['code','label','tone','ends_on','days']
|
||||||
|
* days = giorni rimasti (active/expiring/trial), di tolleranza rimasti (grace), da quanto è scaduto (expired)
|
||||||
|
*/
|
||||||
|
public static function state(array $school, ?string $today = null): array
|
||||||
|
{
|
||||||
|
$today = $today ?? date('Y-m-d');
|
||||||
|
$paid = $school['paid_until'] ?: null;
|
||||||
|
$trial = $school['trial_until'] ?: null;
|
||||||
|
$remind = max(0, (int) self::get('reminder_days', 15));
|
||||||
|
$grace = max(0, (int) self::get('grace_days', 7));
|
||||||
|
|
||||||
|
if (($school['billing_exempt'] ?? 'N') === 'Y') {
|
||||||
|
return ['code' => 'exempt', 'label' => 'Gratuito', 'tone' => 'ok', 'ends_on' => null, 'days' => null];
|
||||||
|
}
|
||||||
|
if ($paid && $paid >= $today) {
|
||||||
|
$d = self::days($today, $paid);
|
||||||
|
return $d <= $remind
|
||||||
|
? ['code' => 'expiring', 'label' => 'In scadenza', 'tone' => 'warn', 'ends_on' => $paid, 'days' => $d]
|
||||||
|
: ['code' => 'active', 'label' => 'Attivo', 'tone' => 'ok', 'ends_on' => $paid, 'days' => $d];
|
||||||
|
}
|
||||||
|
if ($trial && $trial >= $today) {
|
||||||
|
return ['code' => 'trial', 'label' => 'In prova', 'tone' => 'info', 'ends_on' => $trial, 'days' => self::days($today, $trial)];
|
||||||
|
}
|
||||||
|
if (!$paid && !$trial) {
|
||||||
|
return ['code' => 'none', 'label' => 'Non attivo', 'tone' => 'muted', 'ends_on' => null, 'days' => null];
|
||||||
|
}
|
||||||
|
$end = max((string) $paid, (string) $trial);
|
||||||
|
$graceEnd = (new DateTimeImmutable($end))->modify('+' . $grace . ' days')->format('Y-m-d');
|
||||||
|
if ($today <= $graceEnd) {
|
||||||
|
return ['code' => 'grace', 'label' => 'Scaduto', 'tone' => 'danger', 'ends_on' => $end, 'days' => self::days($today, $graceEnd)];
|
||||||
|
}
|
||||||
|
return ['code' => 'expired', 'label' => 'Scaduto', 'tone' => 'danger', 'ends_on' => $end, 'days' => self::days($end, $today)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Aggiunge mesi senza "sforare" (31 gennaio + 1 mese = 28/29 febbraio) */
|
||||||
|
private static function addMonths(DateTimeImmutable $d, int $months): DateTimeImmutable
|
||||||
|
{
|
||||||
|
$y = (int) $d->format('Y');
|
||||||
|
$m = (int) $d->format('n') + $months;
|
||||||
|
$y += intdiv($m - 1, 12);
|
||||||
|
$m = (($m - 1) % 12) + 1;
|
||||||
|
$last = (int) (new DateTimeImmutable(sprintf('%04d-%02d-01', $y, $m)))->format('t');
|
||||||
|
return $d->setDate($y, $m, min((int) $d->format('j'), $last));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prossimo periodo pagato: parte dal giorno dopo la scadenza attuale
|
||||||
|
* (abbonamento o prova) se non è ancora passata, altrimenti da oggi.
|
||||||
|
* @return array [from, to] (Y-m-d)
|
||||||
|
*/
|
||||||
|
public static function nextPeriod(array $school, string $cycle, ?string $today = null): array
|
||||||
|
{
|
||||||
|
$today = $today ?? date('Y-m-d');
|
||||||
|
$lastEnd = max((string) ($school['paid_until'] ?? ''), (string) ($school['trial_until'] ?? ''));
|
||||||
|
$from = ($lastEnd !== '' && $lastEnd >= $today)
|
||||||
|
? (new DateTimeImmutable($lastEnd))->modify('+1 day')
|
||||||
|
: new DateTimeImmutable($today);
|
||||||
|
$to = self::addMonths($from, $cycle === 'month' ? 1 : 12)->modify('-1 day');
|
||||||
|
return [$from->format('Y-m-d'), $to->format('Y-m-d')];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* Ordini
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
public static function order(int $idorder, ?int $idschool = null): ?array
|
||||||
|
{
|
||||||
|
$sql = "SELECT o.*, s.name AS school_name FROM platform_orders o JOIN schools s ON s.idschool = o.idschool WHERE o.idorder = ?";
|
||||||
|
$args = [$idorder];
|
||||||
|
if ($idschool !== null) {
|
||||||
|
$sql .= " AND o.idschool = ?";
|
||||||
|
$args[] = $idschool;
|
||||||
|
}
|
||||||
|
$st = self::pdo()->prepare($sql);
|
||||||
|
$st->execute($args);
|
||||||
|
return $st->fetch(PDO::FETCH_ASSOC) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un ordine "in attesa".
|
||||||
|
* $opt: amount_net (importo IVA esclusa diverso dal listino), notes, allow_inactive (solo superadmin)
|
||||||
|
* @throws RuntimeException con messaggio leggibile
|
||||||
|
*/
|
||||||
|
public static function createOrder(int $idschool, int $idplan, string $cycle, string $method, ?int $userId, array $opt = []): array
|
||||||
|
{
|
||||||
|
if (!isset(self::CYCLES[$cycle]) || !isset(self::METHODS[$method])) {
|
||||||
|
throw new RuntimeException('Dati dell\'ordine non validi.');
|
||||||
|
}
|
||||||
|
$school = self::school($idschool);
|
||||||
|
$plan = self::plan($idplan);
|
||||||
|
if (!$school || !$plan || ($plan['active'] !== 'Y' && empty($opt['allow_inactive']))) {
|
||||||
|
throw new RuntimeException('Piano non disponibile.');
|
||||||
|
}
|
||||||
|
$net = isset($opt['amount_net']) ? (float) $opt['amount_net'] : self::price($plan, $cycle);
|
||||||
|
if ($net === null || $net < 0) {
|
||||||
|
throw new RuntimeException('Questo piano non prevede il pagamento ' . strtolower(self::CYCLES[$cycle]) . '.');
|
||||||
|
}
|
||||||
|
[$net, $rate, $vat, $total] = self::quote($net);
|
||||||
|
[$from, $to] = self::nextPeriod($school, $cycle);
|
||||||
|
|
||||||
|
$snapshot = [];
|
||||||
|
foreach (['name', 'legal_name', 'vat_number', 'tax_code', 'sdi_code', 'pec', 'email', 'billing_email', 'address', 'postcode', 'city', 'province', 'country'] as $k) {
|
||||||
|
$snapshot[$k] = $school[$k] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$pdo->prepare(
|
||||||
|
"INSERT INTO platform_orders
|
||||||
|
(idschool, idplan, plan_name, cycle, period_from, period_to, amount_net, vat_rate, vat_amount, total,
|
||||||
|
currency, method, status, due_date, billing_snapshot, notes, created_by)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'EUR', ?, 'pending', ?, ?, ?, ?)"
|
||||||
|
)->execute([
|
||||||
|
$idschool,
|
||||||
|
$idplan,
|
||||||
|
$plan['name'],
|
||||||
|
$cycle,
|
||||||
|
$from,
|
||||||
|
$to,
|
||||||
|
$net,
|
||||||
|
$rate,
|
||||||
|
$vat,
|
||||||
|
$total,
|
||||||
|
$method,
|
||||||
|
$method === 'bank' ? date('Y-m-d', strtotime('+' . max(1, (int) self::get('bank_due_days', 7)) . ' days')) : null,
|
||||||
|
json_encode($snapshot, JSON_UNESCAPED_UNICODE),
|
||||||
|
isset($opt['notes']) && trim((string) $opt['notes']) !== '' ? trim((string) $opt['notes']) : null,
|
||||||
|
$userId ?: null,
|
||||||
|
]);
|
||||||
|
$id = (int) $pdo->lastInsertId();
|
||||||
|
$number = sprintf('YB-%s-%05d', date('Y'), $id);
|
||||||
|
|
||||||
|
$reference = null;
|
||||||
|
if ($method === 'bank') {
|
||||||
|
$tpl = trim((string) self::get('bank_reference')) ?: self::DEFAULTS['bank_reference'];
|
||||||
|
$reference = mb_substr(strtr($tpl, ['{ordine}' => $number, '{scuola}' => (string) $school['name']]), 0, 140);
|
||||||
|
}
|
||||||
|
$pdo->prepare("UPDATE platform_orders SET number = ?, bank_reference = ? WHERE idorder = ?")
|
||||||
|
->execute([$number, $reference, $id]);
|
||||||
|
|
||||||
|
return self::order($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Segna l'ordine come pagato ed estende l'abbonamento della scuola.
|
||||||
|
* Idempotente: se l'ordine non è più "in attesa" non fa nulla e restituisce false.
|
||||||
|
*/
|
||||||
|
public static function markPaid(int $idorder, ?int $confirmedBy = null, ?string $paymentIntent = null): bool
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
$st = $pdo->prepare("SELECT * FROM platform_orders WHERE idorder = ? FOR UPDATE");
|
||||||
|
$st->execute([$idorder]);
|
||||||
|
$o = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$o || $o['status'] !== 'pending') {
|
||||||
|
$pdo->rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ? FOR UPDATE");
|
||||||
|
$st->execute([(int) $o['idschool']]);
|
||||||
|
$school = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Il periodo definitivo si calcola adesso (un bonifico può arrivare dopo giorni)
|
||||||
|
[$from, $to] = self::nextPeriod($school, $o['cycle']);
|
||||||
|
|
||||||
|
$pdo->prepare(
|
||||||
|
"UPDATE platform_orders
|
||||||
|
SET status = 'paid', paid_at = NOW(), period_from = ?, period_to = ?, confirmed_by = ?,
|
||||||
|
stripe_payment_intent = COALESCE(?, stripe_payment_intent)
|
||||||
|
WHERE idorder = ?"
|
||||||
|
)->execute([$from, $to, $confirmedBy ?: null, $paymentIntent, $idorder]);
|
||||||
|
|
||||||
|
$pdo->prepare(
|
||||||
|
"UPDATE schools
|
||||||
|
SET paid_until = ?, idplan = COALESCE(?, idplan), billing_cycle = ?,
|
||||||
|
status = IF(status IN ('trial', 'suspended'), 'active', status)
|
||||||
|
WHERE idschool = ?"
|
||||||
|
)->execute([$to, $o['idplan'], $o['cycle'], (int) $o['idschool']]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
return true;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Annulla un ordine in attesa (eventualmente solo se della scuola indicata) */
|
||||||
|
public static function cancelOrder(int $idorder, ?int $idschool = null): bool
|
||||||
|
{
|
||||||
|
$sql = "UPDATE platform_orders SET status = 'cancelled' WHERE idorder = ? AND status = 'pending'";
|
||||||
|
$args = [$idorder];
|
||||||
|
if ($idschool !== null) {
|
||||||
|
$sql .= " AND idschool = ?";
|
||||||
|
$args[] = $idschool;
|
||||||
|
}
|
||||||
|
$st = self::pdo()->prepare($sql);
|
||||||
|
$st->execute($args);
|
||||||
|
return $st->rowCount() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* Stripe (API REST diretta)
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
/** @throws RuntimeException */
|
||||||
|
public static function stripeRequest(string $method, string $path, array $params = [], array $headers = []): array
|
||||||
|
{
|
||||||
|
$secret = self::stripeSecret();
|
||||||
|
if ($secret === '') {
|
||||||
|
throw new RuntimeException('Pagamento con carta non configurato.');
|
||||||
|
}
|
||||||
|
$url = 'https://api.stripe.com/v1/' . ltrim($path, '/');
|
||||||
|
$ch = curl_init();
|
||||||
|
$opt = [
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_USERPWD => $secret . ':',
|
||||||
|
CURLOPT_TIMEOUT => 30,
|
||||||
|
CURLOPT_HTTPHEADER => $headers,
|
||||||
|
];
|
||||||
|
if ($method === 'GET') {
|
||||||
|
$opt[CURLOPT_URL] = $url . ($params ? '?' . http_build_query($params) : '');
|
||||||
|
} else {
|
||||||
|
$opt[CURLOPT_URL] = $url;
|
||||||
|
$opt[CURLOPT_POST] = true;
|
||||||
|
$opt[CURLOPT_POSTFIELDS] = http_build_query($params);
|
||||||
|
}
|
||||||
|
curl_setopt_array($ch, $opt);
|
||||||
|
$body = curl_exec($ch);
|
||||||
|
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
$err = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($body === false) {
|
||||||
|
error_log('[PlatformBilling] Stripe curl: ' . $err);
|
||||||
|
throw new RuntimeException('Impossibile contattare il servizio di pagamento. Riprova tra poco.');
|
||||||
|
}
|
||||||
|
$data = json_decode((string) $body, true);
|
||||||
|
if ($code >= 400 || !is_array($data)) {
|
||||||
|
error_log('[PlatformBilling] Stripe ' . $code . ': ' . substr((string) $body, 0, 500));
|
||||||
|
throw new RuntimeException('Il servizio di pagamento ha rifiutato la richiesta. Riprova o scegli il bonifico.');
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Crea la sessione Stripe Checkout per un ordine e restituisce l'URL di pagamento */
|
||||||
|
public static function stripeCheckout(array $order, array $school): string
|
||||||
|
{
|
||||||
|
$base = self::appUrl();
|
||||||
|
$params = [
|
||||||
|
'mode' => 'payment',
|
||||||
|
'client_reference_id' => (string) $order['idorder'],
|
||||||
|
'success_url' => $base . '/subscription.php?checkout=done&o=' . (int) $order['idorder'],
|
||||||
|
'cancel_url' => $base . '/subscription.php?checkout=cancel&o=' . (int) $order['idorder'],
|
||||||
|
'line_items' => [[
|
||||||
|
'quantity' => 1,
|
||||||
|
'price_data' => [
|
||||||
|
'currency' => 'eur',
|
||||||
|
'unit_amount' => (int) round((float) $order['total'] * 100),
|
||||||
|
'product_data' => [
|
||||||
|
'name' => 'YogiBook · ' . $order['plan_name'] . ' (' . strtolower(self::CYCLES[$order['cycle']] ?? '') . ')',
|
||||||
|
'description' => 'Ordine ' . $order['number'] . ' · ' . $school['name'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]],
|
||||||
|
'metadata' => ['idorder' => (string) $order['idorder'], 'idschool' => (string) $order['idschool'], 'number' => (string) $order['number']],
|
||||||
|
'payment_intent_data' => ['metadata' => ['idorder' => (string) $order['idorder'], 'number' => (string) $order['number']]],
|
||||||
|
];
|
||||||
|
$email = $school['billing_email'] ?: $school['email'];
|
||||||
|
if ($email && filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$params['customer_email'] = $email;
|
||||||
|
}
|
||||||
|
|
||||||
|
$session = self::stripeRequest('POST', 'checkout/sessions', $params, ['Idempotency-Key: yb-platform-order-' . (int) $order['idorder']]);
|
||||||
|
if (empty($session['id']) || empty($session['url'])) {
|
||||||
|
throw new RuntimeException('Risposta del servizio di pagamento non valida.');
|
||||||
|
}
|
||||||
|
self::pdo()->prepare("UPDATE platform_orders SET stripe_session_id = ? WHERE idorder = ?")
|
||||||
|
->execute([$session['id'], (int) $order['idorder']]);
|
||||||
|
return $session['url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlla una sessione Checkout e, se pagata e coerente con l'ordine, lo segna pagato.
|
||||||
|
* Usata dal webhook e al ritorno dalla pagina di pagamento (utile anche in locale senza webhook).
|
||||||
|
*/
|
||||||
|
public static function applyStripeSession(array $session): bool
|
||||||
|
{
|
||||||
|
$idorder = (int) ($session['metadata']['idorder'] ?? 0);
|
||||||
|
if ($idorder <= 0 || ($session['payment_status'] ?? '') !== 'paid') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$o = self::order($idorder);
|
||||||
|
if (!$o || $o['method'] !== 'stripe') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($o['stripe_session_id'] && $o['stripe_session_id'] !== ($session['id'] ?? '')) {
|
||||||
|
error_log('[PlatformBilling] sessione Stripe diversa per ordine ' . $idorder);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$expected = (int) round((float) $o['total'] * 100);
|
||||||
|
if ((int) ($session['amount_total'] ?? -1) !== $expected || strtolower((string) ($session['currency'] ?? '')) !== 'eur') {
|
||||||
|
error_log('[PlatformBilling] importo Stripe non coerente per ordine ' . $idorder);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$pi = $session['payment_intent'] ?? null;
|
||||||
|
return self::markPaid($idorder, null, is_string($pi) ? $pi : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stripeSync(array $order): bool
|
||||||
|
{
|
||||||
|
if ($order['status'] !== 'pending' || $order['method'] !== 'stripe' || empty($order['stripe_session_id'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$session = self::stripeRequest('GET', 'checkout/sessions/' . rawurlencode($order['stripe_session_id']));
|
||||||
|
return self::applyStripeSession($session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Verifica la firma "Stripe-Signature" di un webhook */
|
||||||
|
public static function stripeVerify(string $payload, string $header, string $secret, int $tolerance = 300): bool
|
||||||
|
{
|
||||||
|
if ($secret === '' || $header === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$t = null;
|
||||||
|
$sigs = [];
|
||||||
|
foreach (explode(',', $header) as $part) {
|
||||||
|
$kv = explode('=', trim($part), 2);
|
||||||
|
if (count($kv) !== 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($kv[0] === 't') {
|
||||||
|
$t = (int) $kv[1];
|
||||||
|
} elseif ($kv[0] === 'v1') {
|
||||||
|
$sigs[] = $kv[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$t || !$sigs || abs(time() - $t) > $tolerance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$expected = hash_hmac('sha256', $t . '.' . $payload, $secret);
|
||||||
|
foreach ($sigs as $s) {
|
||||||
|
if (hash_equals($expected, $s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,322 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SchoolContext v3
|
||||||
|
* - Scuola corrente dell'utente loggato e ruolo nella scuola
|
||||||
|
* - Scuole tra cui può passare (owner multi-scuola, superadmin)
|
||||||
|
* - Vista attiva (superadmin | school | teacher | student): permette a chi ha
|
||||||
|
* permessi alti di vedere l'app come un livello inferiore. Mai superiore.
|
||||||
|
*
|
||||||
|
* Uso (headscript):
|
||||||
|
* $schoolData = SchoolContext::resolve((int)$iduserlogin);
|
||||||
|
* $idschool = SchoolContext::id();
|
||||||
|
*
|
||||||
|
* I controlli isSuperadmin()/isSchoolAdmin()/isStaff() tengono conto della
|
||||||
|
* vista attiva. viewModes() e available() usano i permessi REALI.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class SchoolContext
|
||||||
|
{
|
||||||
|
/** Scuola di fallback durante la fase monoscuola (Seregno) */
|
||||||
|
const DEFAULT_SCHOOL = 1;
|
||||||
|
|
||||||
|
/** @var array|null scuola corrente (riga schools + school_role) */
|
||||||
|
private static $school = null;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private static $userId = 0;
|
||||||
|
|
||||||
|
/** @var bool permesso REALE di superadmin */
|
||||||
|
private static $superadmin = false;
|
||||||
|
|
||||||
|
/** @var array scuole di cui l'utente è membro */
|
||||||
|
private static $memberships = [];
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* RISOLUZIONE SCUOLA */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
public static function resolve(int $userId): array
|
||||||
|
{
|
||||||
|
if (self::$school !== null) {
|
||||||
|
return self::$school;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = self::pdo();
|
||||||
|
self::$userId = $userId;
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT is_superadmin FROM auth_users WHERE id = ?");
|
||||||
|
$st->execute([$userId]);
|
||||||
|
self::$superadmin = ($st->fetchColumn() === 'Y');
|
||||||
|
|
||||||
|
self::$memberships = self::loadMemberships($userId);
|
||||||
|
|
||||||
|
// TEMPORANEO (fase monoscuola): utente senza scuola -> agganciato a Seregno
|
||||||
|
if (empty(self::$memberships) && !self::$superadmin) {
|
||||||
|
$ins = $pdo->prepare(
|
||||||
|
"INSERT IGNORE INTO school_user (user_id, idschool, school_role)
|
||||||
|
VALUES (?, ?, 'student')"
|
||||||
|
);
|
||||||
|
$ins->execute([$userId, self::DEFAULT_SCHOOL]);
|
||||||
|
self::$memberships = self::loadMemberships($userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$requested = isset($_SESSION['idschool']) ? (int) $_SESSION['idschool'] : 0;
|
||||||
|
$selected = self::pick($requested);
|
||||||
|
|
||||||
|
if ($selected === null) {
|
||||||
|
http_response_code(403);
|
||||||
|
die('Nessuna scuola attiva associata a questo account.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$selected['idschool'] = (int) $selected['idschool'];
|
||||||
|
$_SESSION['idschool'] = $selected['idschool'];
|
||||||
|
|
||||||
|
self::$school = $selected;
|
||||||
|
return self::$school;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cambia scuola corrente. False se l'utente non può accedervi. */
|
||||||
|
public static function switchTo(int $idschool): bool
|
||||||
|
{
|
||||||
|
if ($idschool <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (self::available() as $s) {
|
||||||
|
if ((int) $s['idschool'] === $idschool) {
|
||||||
|
$_SESSION['idschool'] = $idschool;
|
||||||
|
self::$school = null;
|
||||||
|
self::resolve(self::$userId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scuole selezionabili (permessi reali). Superadmin: tutte. */
|
||||||
|
public static function available(): array
|
||||||
|
{
|
||||||
|
if (!self::$superadmin) {
|
||||||
|
return self::$memberships;
|
||||||
|
}
|
||||||
|
|
||||||
|
$roles = [];
|
||||||
|
foreach (self::$memberships as $m) {
|
||||||
|
$roles[(int) $m['idschool']] = $m['school_role'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$all = self::pdo()->query("SELECT * FROM schools ORDER BY name")->fetchAll();
|
||||||
|
foreach ($all as &$s) {
|
||||||
|
$s['school_role'] = $roles[(int) $s['idschool']] ?? 'superadmin';
|
||||||
|
}
|
||||||
|
unset($s);
|
||||||
|
return $all;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* VISTA ATTIVA */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Viste consentite in base ai permessi REALI, dalla più alta alla più bassa.
|
||||||
|
* @return array chiave => etichetta
|
||||||
|
*/
|
||||||
|
public static function viewModes(): array
|
||||||
|
{
|
||||||
|
$real = self::realRole();
|
||||||
|
$modes = [];
|
||||||
|
|
||||||
|
if (self::$superadmin) {
|
||||||
|
$modes['superadmin'] = 'Superadmin';
|
||||||
|
}
|
||||||
|
if (self::$superadmin || in_array($real, ['owner', 'admin'], true)) {
|
||||||
|
$modes['school'] = 'Scuola';
|
||||||
|
}
|
||||||
|
if ($real === 'teacher') {
|
||||||
|
$modes['teacher'] = 'Insegnante';
|
||||||
|
}
|
||||||
|
$modes['student'] = 'Allievo';
|
||||||
|
|
||||||
|
return $modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vista attiva (se quella in sessione non è consentita: la più alta) */
|
||||||
|
public static function viewMode(): string
|
||||||
|
{
|
||||||
|
$modes = self::viewModes();
|
||||||
|
$req = $_SESSION['view_mode'] ?? '';
|
||||||
|
if (isset($modes[$req])) {
|
||||||
|
return $req;
|
||||||
|
}
|
||||||
|
return (string) array_key_first($modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setViewMode(string $mode): bool
|
||||||
|
{
|
||||||
|
if (!isset(self::viewModes()[$mode])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['view_mode'] = $mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Pagina iniziale per la vista attiva */
|
||||||
|
public static function landingPage(): string
|
||||||
|
{
|
||||||
|
switch (self::viewMode()) {
|
||||||
|
case 'superadmin':
|
||||||
|
return 'sa-dashboard.php';
|
||||||
|
case 'school':
|
||||||
|
return 'dashboard.php';
|
||||||
|
case 'teacher':
|
||||||
|
return 'adminpanel.php';
|
||||||
|
default:
|
||||||
|
return 'studentdashboard.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* GETTER E CONTROLLI (tengono conto della vista) */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
public static function id(): int
|
||||||
|
{
|
||||||
|
return self::get()['idschool'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get(): array
|
||||||
|
{
|
||||||
|
if (self::$school === null) {
|
||||||
|
throw new RuntimeException('SchoolContext::resolve() non ancora chiamato');
|
||||||
|
}
|
||||||
|
return self::$school;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ruolo REALE nella scuola: owner|admin|teacher|student|superadmin */
|
||||||
|
public static function realRole(): string
|
||||||
|
{
|
||||||
|
return self::get()['school_role'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Alias storico di realRole() */
|
||||||
|
public static function role(): string
|
||||||
|
{
|
||||||
|
return self::realRole();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isRealSuperadmin(): bool
|
||||||
|
{
|
||||||
|
return self::$superadmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isSuperadmin(): bool
|
||||||
|
{
|
||||||
|
return self::viewMode() === 'superadmin';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isOwner(): bool
|
||||||
|
{
|
||||||
|
return self::realRole() === 'owner' && self::isSchoolAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gestisce la scuola (vista superadmin o scuola) */
|
||||||
|
public static function isSchoolAdmin(): bool
|
||||||
|
{
|
||||||
|
return in_array(self::viewMode(), ['superadmin', 'school'], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Staff: amministratori + insegnanti */
|
||||||
|
public static function isStaff(): bool
|
||||||
|
{
|
||||||
|
return self::isSchoolAdmin() || self::viewMode() === 'teacher';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function requireSchoolAdmin(): void
|
||||||
|
{
|
||||||
|
if (!self::isSchoolAdmin()) {
|
||||||
|
self::deny();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function requireStaff(): void
|
||||||
|
{
|
||||||
|
if (!self::isStaff()) {
|
||||||
|
self::deny();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function requireSuperadmin(): void
|
||||||
|
{
|
||||||
|
if (!self::isSuperadmin()) {
|
||||||
|
self::deny();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* INTERNI */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
private static function deny(): void
|
||||||
|
{
|
||||||
|
http_response_code(403);
|
||||||
|
$home = self::$school ? self::landingPage() : 'userpanel.php';
|
||||||
|
die('Accesso non autorizzato con la vista attuale. <a href="' . $home . '">Torna alla pagina iniziale</a>');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pick(int $requested): ?array
|
||||||
|
{
|
||||||
|
foreach (self::$memberships as $m) {
|
||||||
|
if ((int) $m['idschool'] === $requested) {
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$superadmin) {
|
||||||
|
$pdo = self::pdo();
|
||||||
|
if ($requested > 0) {
|
||||||
|
$st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ?");
|
||||||
|
$st->execute([$requested]);
|
||||||
|
$row = $st->fetch();
|
||||||
|
if ($row) {
|
||||||
|
$row['school_role'] = 'superadmin';
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty(self::$memberships)) {
|
||||||
|
return self::$memberships[0];
|
||||||
|
}
|
||||||
|
$row = $pdo->query("SELECT * FROM schools ORDER BY idschool LIMIT 1")->fetch();
|
||||||
|
if ($row) {
|
||||||
|
$row['school_role'] = 'superadmin';
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$memberships[0] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function loadMemberships(int $userId): array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT s.*, su.school_role
|
||||||
|
FROM school_user su
|
||||||
|
JOIN schools s ON s.idschool = su.idschool
|
||||||
|
WHERE su.user_id = ?
|
||||||
|
AND su.active = 'Y'
|
||||||
|
AND s.status <> 'suspended'
|
||||||
|
ORDER BY s.name"
|
||||||
|
);
|
||||||
|
$st->execute([$userId]);
|
||||||
|
return $st->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SchoolMail
|
||||||
|
* Email agli allievi a nome di una scuola, con il template standard (mail/emailtemplate2.php).
|
||||||
|
* Se l'invio fallisce registra l'errore e ritorna false: non blocca mai l'operazione.
|
||||||
|
*
|
||||||
|
* SchoolMail::toStudent($email, $firstname, 'Oggetto', ['riga 1', 'riga 2']);
|
||||||
|
* SchoolMail::toStudent($email, $firstname, 'Oggetto', $lines, '', $schoolRow, true); // copia alla scuola
|
||||||
|
* SchoolMail::toMany([['email'=>..,'first_name'=>..], ...], 'Oggetto', $lines); // invio di massa
|
||||||
|
* SchoolMail::sendHtml($email, $nome, 'Oggetto', $htmlCompleto, $schoolRow, $ccEmail); // HTML già pronto
|
||||||
|
* SchoolMail::custom($email, 'Oggetto', $lines); // testo libero, senza saluto automatico
|
||||||
|
*
|
||||||
|
* Le righe sono HTML: i dati variabili vanno passati già con htmlspecialchars().
|
||||||
|
*/
|
||||||
|
|
||||||
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
|
use PHPMailer\PHPMailer\Exception;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/mailer.php';
|
||||||
|
|
||||||
|
class SchoolMail
|
||||||
|
{
|
||||||
|
public static function toStudent(
|
||||||
|
string $to,
|
||||||
|
string $firstName,
|
||||||
|
string $subject,
|
||||||
|
array $lines,
|
||||||
|
string $altText = '',
|
||||||
|
?array $school = null,
|
||||||
|
bool $ccSchool = false
|
||||||
|
): bool {
|
||||||
|
if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$school = $school ?? SchoolContext::get();
|
||||||
|
$mail = self::mailer($school);
|
||||||
|
try {
|
||||||
|
$mail->addAddress($to);
|
||||||
|
if ($ccSchool && !empty($school['email']) && filter_var($school['email'], FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$mail->addCC($school['email'], (string) $school['name']);
|
||||||
|
}
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = self::render($firstName, $lines, $school);
|
||||||
|
$mail->AltBody = $altText !== '' ? $altText : strip_tags(implode("\n", $lines));
|
||||||
|
$mail->send();
|
||||||
|
return true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('SchoolMail error (' . $to . '): ' . $mail->ErrorInfo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email scritta dalla scuola (invio singolo o di massa da Situazione allievi):
|
||||||
|
* nessun saluto automatico, perché il testo lo contiene già.
|
||||||
|
* Le righe sono HTML già pulito.
|
||||||
|
*/
|
||||||
|
public static function custom(string $to, string $subject, array $lines, ?array $school = null): bool
|
||||||
|
{
|
||||||
|
if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$school = $school ?? SchoolContext::get();
|
||||||
|
$mail = self::mailer($school);
|
||||||
|
try {
|
||||||
|
$mail->addAddress($to);
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = self::render('', $lines, $school, false);
|
||||||
|
$mail->AltBody = self::htmlToText(implode("\n\n", $lines));
|
||||||
|
$mail->send();
|
||||||
|
return true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('SchoolMail custom error (' . $to . '): ' . $mail->ErrorInfo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invio di massa con una sola connessione SMTP.
|
||||||
|
* @param array $recipients [['email' => ..., 'first_name' => ...], ...]
|
||||||
|
* @return array{sent:int, failed:int}
|
||||||
|
*/
|
||||||
|
public static function toMany(array $recipients, string $subject, array $lines, ?array $school = null): array
|
||||||
|
{
|
||||||
|
$school = $school ?? SchoolContext::get();
|
||||||
|
$mail = self::mailer($school);
|
||||||
|
$mail->SMTPKeepAlive = true;
|
||||||
|
$sent = 0;
|
||||||
|
$failed = 0;
|
||||||
|
|
||||||
|
foreach ($recipients as $r) {
|
||||||
|
$to = (string) ($r['email'] ?? '');
|
||||||
|
if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$failed++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$mail->clearAddresses();
|
||||||
|
$mail->addAddress($to);
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = self::render((string) ($r['first_name'] ?? ''), $lines, $school);
|
||||||
|
$mail->AltBody = strip_tags(implode("\n", $lines));
|
||||||
|
$mail->send();
|
||||||
|
$sent++;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('SchoolMail bulk error (' . $to . '): ' . $mail->ErrorInfo);
|
||||||
|
$failed++;
|
||||||
|
$mail->getSMTPInstance()->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$mail->smtpClose();
|
||||||
|
return ['sent' => $sent, 'failed' => $failed];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invio di un'email con HTML già composto (es. layout degli eventi).
|
||||||
|
* Funziona anche senza sessione se si passa $school (endpoint pubblici, cron).
|
||||||
|
* $cc: indirizzo in copia (ignorato se non valido o uguale al destinatario).
|
||||||
|
*/
|
||||||
|
public static function sendHtml(
|
||||||
|
string $to,
|
||||||
|
string $toName,
|
||||||
|
string $subject,
|
||||||
|
string $html,
|
||||||
|
?array $school = null,
|
||||||
|
string $cc = ''
|
||||||
|
): bool {
|
||||||
|
if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$school = $school ?? SchoolContext::get();
|
||||||
|
$mail = self::mailer($school);
|
||||||
|
$mail->addAddress($to, $toName);
|
||||||
|
if ($cc !== '' && filter_var($cc, FILTER_VALIDATE_EMAIL) && strcasecmp($cc, $to) !== 0) {
|
||||||
|
$mail->addCC($cc, (string) ($school['name'] ?? ''));
|
||||||
|
}
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = $html;
|
||||||
|
$mail->AltBody = self::htmlToText($html);
|
||||||
|
$mail->send();
|
||||||
|
return true;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
error_log('SchoolMail sendHtml error (' . $to . '): ' . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
private static function htmlToText(string $html): string
|
||||||
|
{
|
||||||
|
$text = str_replace(['</p>', '<br>', '<br/>', '<br />', '</div>', '</tr>'], "\n", $html);
|
||||||
|
return trim(preg_replace('/\n{3,}/', "\n\n", html_entity_decode(strip_tags($text), ENT_QUOTES, 'UTF-8')));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function mailer(array $school): PHPMailer
|
||||||
|
{
|
||||||
|
$schoolName = (string) ($school['name'] ?? 'YogiBook');
|
||||||
|
$mail = new PHPMailer(true);
|
||||||
|
$mail->isSMTP();
|
||||||
|
$mail->Host = $_ENV['MAIL_HOST'];
|
||||||
|
$mail->SMTPAuth = true;
|
||||||
|
$mail->Username = $_ENV['MAIL_USERNAME'];
|
||||||
|
$mail->Password = $_ENV['MAIL_PASSWORD'];
|
||||||
|
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'];
|
||||||
|
$mail->Port = (int) $_ENV['MAIL_PORT'];
|
||||||
|
$mail->CharSet = 'UTF-8';
|
||||||
|
$mail->Timeout = 20;
|
||||||
|
$mail->isHTML(true);
|
||||||
|
$mail->setFrom($_ENV['MAIL_FROM_ADDRESS'], $schoolName ?: ($_ENV['MAIL_FROM_NAME'] ?? 'YogiBook'));
|
||||||
|
if (!empty($school['email']) && filter_var($school['email'], FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$mail->addReplyTo($school['email'], $schoolName);
|
||||||
|
}
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function render(string $firstName, array $lines, array $school, bool $greet = true): string
|
||||||
|
{
|
||||||
|
$schoolName = (string) ($school['name'] ?? 'YogiBook');
|
||||||
|
$appUrl = rtrim($_ENV['APP_URL'] ?? 'https://yogibook.yogasoul.it', '/');
|
||||||
|
$h = fn($v) => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
|
||||||
|
$p = "<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 16px; line-height: 30.4px;'>";
|
||||||
|
$pe = "</span></p>";
|
||||||
|
$btn = "box-sizing: border-box; display: inline-block; text-decoration: none; text-align: center; color: #FFFFFF; background-color: #3AAEE0; border-radius: 4px; font-size: 14px;";
|
||||||
|
|
||||||
|
$greeting = trim($firstName) !== '' ? 'Ciao ' . $h($firstName) . ',' : 'Ciao,';
|
||||||
|
$body = $greet
|
||||||
|
? "<p style='font-size: 14px; line-height: 190%;'><span style='font-size: 18px; line-height: 34.2px;'><strong>{$greeting}</strong></span></p>"
|
||||||
|
: '';
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$body .= $p . $line . $pe;
|
||||||
|
}
|
||||||
|
$body .= "<br>{$p}Per vedere e gestire le tue lezioni: <a href='{$appUrl}'>YogiBook</a>{$pe}"
|
||||||
|
. "<br>{$p}Se non ricordi la password o non sei mai entrata/o in YogiBook, reimpostala da qui:{$pe}<br>"
|
||||||
|
. "<a href='{$appUrl}/password/reset' target='_blank' style='{$btn}'><span style='display: block; padding: 10px 20px; line-height: 120%;'>Reimposta password</span></a>"
|
||||||
|
. "<br><br>{$p}Ci vediamo sul tappetino!{$pe}{$p}" . $h($schoolName) . $pe;
|
||||||
|
|
||||||
|
// Variabili attese dal template
|
||||||
|
$messageedit = $body;
|
||||||
|
$buttonedit = "<a href='{$appUrl}/' target='_blank' class='v-button v-font-size' style='{$btn}'>"
|
||||||
|
. "<span style='display: block; padding: 10px 20px; line-height: 120%;'>YogiBook - " . $h($schoolName) . "</span></a>";
|
||||||
|
$mailmessage1 = '';
|
||||||
|
include __DIR__ . '/../mail/emailtemplate2.php';
|
||||||
|
return $mailmessage1 ?: $body;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SchoolScope
|
||||||
|
* Verifica che record e utenti appartengano alla scuola corrente.
|
||||||
|
* Da usare in ogni pagina/endpoint che riceve un ID dall'esterno.
|
||||||
|
*
|
||||||
|
* Uso:
|
||||||
|
* SchoolScope::assert('bookingclass', $idbookingclass); // blocca con 403 se non è della scuola
|
||||||
|
* if (!SchoolScope::belongs('service', $id)) { ... }
|
||||||
|
* SchoolScope::assertMember($userid); // utente iscritto alla scuola
|
||||||
|
* SchoolScope::addMember($newUserId); // iscrive un nuovo utente come allievo
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class SchoolScope
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Tabelle ammesse e relativa chiave primaria.
|
||||||
|
* (whitelist: i nomi non arrivano mai dall'esterno nella query)
|
||||||
|
*/
|
||||||
|
const TABLES = [
|
||||||
|
'bookingclass' => 'idbookingclass',
|
||||||
|
'serviceschedule' => 'idserviceschedule',
|
||||||
|
'service' => 'idservice',
|
||||||
|
'servicecategory' => 'idservicecategory',
|
||||||
|
'associateclass' => 'idassociateclass',
|
||||||
|
'propagation' => 'idpropagation',
|
||||||
|
'orderbook' => 'idorderbook',
|
||||||
|
'employee' => 'idemployee',
|
||||||
|
'dayoff' => 'iddayoff',
|
||||||
|
'expiryparameter' => 'idexpiryparameter',
|
||||||
|
'certificateuserprofile' => 'idcertificateuserprofile',
|
||||||
|
'events' => 'id',
|
||||||
|
'event_bookings' => 'id',
|
||||||
|
'event_locations' => 'id',
|
||||||
|
'school_images' => 'idimage',
|
||||||
|
'products' => 'idproduct',
|
||||||
|
'product_variants' => 'idvariant',
|
||||||
|
'product_services' => 'idproductservice',
|
||||||
|
'product_images' => 'idimage',
|
||||||
|
'orderbook_services' => 'idorderbookservice',
|
||||||
|
'memberships' => 'idmembership',
|
||||||
|
'gift_vouchers' => 'idvoucher',
|
||||||
|
'coupons' => 'idcoupon',
|
||||||
|
'coupon_products' => 'idcouponproduct',
|
||||||
|
'coupon_redemptions' => 'idredemption',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Il record $id della tabella appartiene alla scuola corrente? */
|
||||||
|
public static function belongs(string $table, int $id, ?int $idschool = null): bool
|
||||||
|
{
|
||||||
|
if ($id <= 0 || !isset(self::TABLES[$table])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$pk = self::TABLES[$table];
|
||||||
|
$st = self::pdo()->prepare("SELECT 1 FROM `$table` WHERE `$pk` = ? AND idschool = ? LIMIT 1");
|
||||||
|
$st->execute([$id, $idschool ?? SchoolContext::id()]);
|
||||||
|
return (bool) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Come belongs(), ma blocca la richiesta (403) se il record non è della scuola */
|
||||||
|
public static function assert(string $table, int $id): void
|
||||||
|
{
|
||||||
|
if (!self::belongs($table, $id)) {
|
||||||
|
self::deny('Elemento non trovato in questa scuola.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** L'utente è membro attivo della scuola corrente? */
|
||||||
|
public static function isMember(int $userId, ?int $idschool = null): bool
|
||||||
|
{
|
||||||
|
if ($userId <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT 1 FROM school_user WHERE user_id = ? AND idschool = ? AND active = 'Y' LIMIT 1"
|
||||||
|
);
|
||||||
|
$st->execute([$userId, $idschool ?? SchoolContext::id()]);
|
||||||
|
return (bool) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function assertMember(int $userId): void
|
||||||
|
{
|
||||||
|
if (!self::isMember($userId)) {
|
||||||
|
self::deny('Utente non iscritto a questa scuola.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iscrive un utente alla scuola corrente (default: allievo).
|
||||||
|
* Se è già membro non cambia il ruolo, lo riattiva soltanto.
|
||||||
|
*/
|
||||||
|
public static function addMember(int $userId, string $role = 'student', ?int $idschool = null): void
|
||||||
|
{
|
||||||
|
if ($userId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self::pdo()->prepare(
|
||||||
|
"INSERT INTO school_user (user_id, idschool, school_role, active)
|
||||||
|
VALUES (?, ?, ?, 'Y')
|
||||||
|
ON DUPLICATE KEY UPDATE active = 'Y'"
|
||||||
|
)->execute([$userId, $idschool ?? SchoolContext::id(), $role]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Risposta 403. Per le chiamate AJAX restituisce JSON,
|
||||||
|
* così il .fail() di jQuery scatta e il messaggio è leggibile.
|
||||||
|
*/
|
||||||
|
private static function deny(string $msg): void
|
||||||
|
{
|
||||||
|
http_response_code(403);
|
||||||
|
$isAjax = (($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest')
|
||||||
|
|| strpos($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') !== false;
|
||||||
|
if ($isAjax) {
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
echo json_encode(['success' => false, 'error' => $msg]);
|
||||||
|
} else {
|
||||||
|
echo htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SchoolSettings
|
||||||
|
* Impostazioni della scuola (tabella `option`, una riga per scuola).
|
||||||
|
* Sostituisce tutti i "SELECT * FROM `option` LIMIT 1".
|
||||||
|
*
|
||||||
|
* Uso:
|
||||||
|
* $timetocancel = (int) SchoolSettings::get('maxbeforetimecancell', 24);
|
||||||
|
* $all = SchoolSettings::all();
|
||||||
|
* SchoolSettings::save(['show_teacher' => 'Y']);
|
||||||
|
*
|
||||||
|
* Nei cron (senza sessione) passare l'idschool esplicito:
|
||||||
|
* SchoolSettings::get('show_teacher', 'N', $idschool);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class SchoolSettings
|
||||||
|
{
|
||||||
|
/** @var array cache per scuola: idschool => riga option */
|
||||||
|
private static $cache = [];
|
||||||
|
|
||||||
|
/** Colonne che non si possono modificare con save() */
|
||||||
|
const PROTECTED_COLUMNS = ['idption', 'idschool'];
|
||||||
|
|
||||||
|
/** Tutte le impostazioni della scuola (riga creata se mancante) */
|
||||||
|
public static function all(?int $idschool = null): array
|
||||||
|
{
|
||||||
|
$idschool = self::schoolId($idschool);
|
||||||
|
|
||||||
|
if (!isset(self::$cache[$idschool])) {
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$st = $pdo->prepare("SELECT * FROM `option` WHERE idschool = ? LIMIT 1");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$row = $st->fetch();
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
// Nuova scuola: crea la riga con i default delle colonne
|
||||||
|
try {
|
||||||
|
$pdo->prepare("INSERT INTO `option` (idschool) VALUES (?)")->execute([$idschool]);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$row = $st->fetch();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log('SchoolSettings: impossibile creare option per scuola ' . $idschool . ': ' . $e->getMessage());
|
||||||
|
$row = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$cache[$idschool] = $row ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$cache[$idschool];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Singola impostazione, con default se mancante o NULL */
|
||||||
|
public static function get(string $key, $default = null, ?int $idschool = null)
|
||||||
|
{
|
||||||
|
$all = self::all($idschool);
|
||||||
|
return (array_key_exists($key, $all) && $all[$key] !== null) ? $all[$key] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Salva una o più impostazioni. Accetta solo colonne esistenti in `option`
|
||||||
|
* (le altre chiavi vengono ignorate).
|
||||||
|
*/
|
||||||
|
public static function save(array $data, ?int $idschool = null): void
|
||||||
|
{
|
||||||
|
$idschool = self::schoolId($idschool);
|
||||||
|
$current = self::all($idschool);
|
||||||
|
|
||||||
|
$set = [];
|
||||||
|
$params = [];
|
||||||
|
foreach ($data as $col => $val) {
|
||||||
|
if (!array_key_exists($col, $current) || in_array($col, self::PROTECTED_COLUMNS, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$set[] = "`$col` = ?";
|
||||||
|
$params[] = $val;
|
||||||
|
}
|
||||||
|
if (empty($set)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params[] = $idschool;
|
||||||
|
self::pdo()->prepare("UPDATE `option` SET " . implode(', ', $set) . " WHERE idschool = ?")
|
||||||
|
->execute($params);
|
||||||
|
|
||||||
|
unset(self::$cache[$idschool]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function schoolId(?int $idschool): int
|
||||||
|
{
|
||||||
|
if ($idschool !== null && $idschool > 0) {
|
||||||
|
return $idschool;
|
||||||
|
}
|
||||||
|
return SchoolContext::id();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SchoolSetup
|
||||||
|
* Percorso "Primi passi" per l'owner di una nuova scuola.
|
||||||
|
* Ogni passo si considera fatto guardando i dati reali della scuola;
|
||||||
|
* pochi passi (da verificare a occhio) si segnano a mano. I passi facoltativi si possono saltare.
|
||||||
|
* Lo stato manuale e l'ultimo avanzamento stanno in option.setup_state (JSON).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class SchoolSetup
|
||||||
|
{
|
||||||
|
const PHASES = [
|
||||||
|
'school' => ['La tua scuola', 'Come ti presenti ad allieve e insegnanti'],
|
||||||
|
'classes' => ['Classi e calendario', 'Cosa si può prenotare e quando'],
|
||||||
|
'sell' => ['Vendita', 'Cosa vendi e come ti pagano'],
|
||||||
|
'test' => ['Prova finale', 'Fai un giro completo come farà un\'allieva'],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Stato manuale salvato: ['done' => [key => data], 'skip' => [key => data], 'progress' => 'x/y'] */
|
||||||
|
public static function state(int $idschool): array
|
||||||
|
{
|
||||||
|
$raw = (string) SchoolSettings::get('setup_state', '', $idschool);
|
||||||
|
$s = json_decode($raw, true);
|
||||||
|
return is_array($s) ? $s + ['done' => [], 'skip' => []] : ['done' => [], 'skip' => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveState(int $idschool, array $state): void
|
||||||
|
{
|
||||||
|
SchoolSettings::save(['setup_state' => json_encode($state, JSON_UNESCAPED_UNICODE)], $idschool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function completed(int $idschool): bool
|
||||||
|
{
|
||||||
|
return (string) SchoolSettings::get('setup_completed_at', '', $idschool) !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Elenco dei passi con stato calcolato */
|
||||||
|
public static function steps(int $idschool, int $userId): array
|
||||||
|
{
|
||||||
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
$one = function (string $sql, array $args) use ($pdo) {
|
||||||
|
$st = $pdo->prepare($sql);
|
||||||
|
$st->execute($args);
|
||||||
|
return $st->fetchColumn();
|
||||||
|
};
|
||||||
|
$state = self::state($idschool);
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ?");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$sc = $st->fetch(PDO::FETCH_ASSOC) ?: [];
|
||||||
|
$filled = fn($k) => trim((string) ($sc[$k] ?? '')) !== '';
|
||||||
|
|
||||||
|
$teachers = (int) $one("SELECT COUNT(*) FROM employee WHERE idschool = ? AND active = 'Y'", [$idschool]);
|
||||||
|
$classes = (int) $one("SELECT COUNT(*) FROM service WHERE idschool = ?", [$idschool]);
|
||||||
|
$future = (int) $one("SELECT COUNT(*) FROM serviceschedule WHERE idschool = ? AND dateschedule > NOW()", [$idschool]);
|
||||||
|
$dayoffs = (int) $one("SELECT COUNT(*) FROM dayoff WHERE idschool = ? AND dayoffdate >= CURDATE()", [$idschool]);
|
||||||
|
$rules = (int) $one("SELECT COUNT(*) FROM expiryparameter WHERE idschool = ?", [$idschool]);
|
||||||
|
$products = (int) $one(
|
||||||
|
"SELECT COUNT(*) FROM products p WHERE p.idschool = ? AND p.active = 'Y'
|
||||||
|
AND EXISTS (SELECT 1 FROM product_variants v WHERE v.idproduct = p.idproduct AND v.active = 'Y')",
|
||||||
|
[$idschool]
|
||||||
|
);
|
||||||
|
$bankOk = SchoolSettings::get('bank_enabled', 'N', $idschool) === 'Y' && trim((string) SchoolSettings::get('bank_iban', '', $idschool)) !== '';
|
||||||
|
$cardOk = SchoolSettings::get('stripe_charges_enabled', 'N', $idschool) === 'Y';
|
||||||
|
$shopOn = SchoolSettings::get('shop_enabled', 'N', $idschool) === 'Y';
|
||||||
|
$testOrder = (int) $one("SELECT COUNT(*) FROM orderbook WHERE idschool = ? AND iduser = ? AND idproduct IS NOT NULL", [$idschool, $userId]);
|
||||||
|
$testDone = (int) $one("SELECT COUNT(*) FROM orderbook WHERE idschool = ? AND iduser = ? AND idproduct IS NOT NULL AND payment_status IN ('paid', 'cancelled')", [$idschool, $userId]);
|
||||||
|
$students = (int) $one("SELECT COUNT(*) FROM school_user WHERE idschool = ? AND school_role = 'student' AND active = 'Y' AND user_id <> ?", [$idschool, $userId]);
|
||||||
|
|
||||||
|
$sub = null;
|
||||||
|
if (is_file(__DIR__ . '/PlatformBilling.php')) {
|
||||||
|
require_once __DIR__ . '/PlatformBilling.php';
|
||||||
|
try {
|
||||||
|
$row = PlatformBilling::school($idschool);
|
||||||
|
$sub = $row ? PlatformBilling::state($row) : null;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
$sub = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$steps = [
|
||||||
|
// ---------------- La scuola
|
||||||
|
[
|
||||||
|
'key' => 'profile',
|
||||||
|
'phase' => 'school',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Dati della scuola',
|
||||||
|
'text' => 'Nome, email, indirizzo e città: compaiono nelle email alle allieve, nella pagina pubblica e nelle ricevute.',
|
||||||
|
'url' => 'optionsschool.php?tab=profile',
|
||||||
|
'cta' => 'Compila i dati',
|
||||||
|
'done' => $filled('name') && $filled('email') && $filled('address') && $filled('city'),
|
||||||
|
'detail' => $filled('email') ? '' : 'Manca l\'email della scuola: serve come mittente delle email.'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'public',
|
||||||
|
'phase' => 'school',
|
||||||
|
'required' => false,
|
||||||
|
'title' => 'Logo e presentazione',
|
||||||
|
'text' => 'Il logo appare in alto nell\'app; slogan e descrizione nella pagina della scuola.',
|
||||||
|
'url' => 'optionsschool.php?tab=public',
|
||||||
|
'cta' => 'Carica il logo',
|
||||||
|
'done' => $filled('logo') && ($filled('short_description') || $filled('description'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'look',
|
||||||
|
'phase' => 'school',
|
||||||
|
'required' => false,
|
||||||
|
'manual' => true,
|
||||||
|
'title' => 'Colori dell\'app',
|
||||||
|
'text' => 'Scegli i colori della tua scuola. Se non li tocchi resta il tema YogiBook.',
|
||||||
|
'url' => 'optionsschool.php?tab=theme',
|
||||||
|
'cta' => 'Scegli i colori',
|
||||||
|
'done' => false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'teachers',
|
||||||
|
'phase' => 'school',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Insegnanti',
|
||||||
|
'text' => 'Aggiungi chi insegna: servono per assegnare le classi. Puoi inserire anche te stessa.',
|
||||||
|
'url' => 'insegnanti.php',
|
||||||
|
'cta' => 'Aggiungi insegnanti',
|
||||||
|
'done' => $teachers > 0,
|
||||||
|
'detail' => $teachers ? $teachers . ' attivi' : ''
|
||||||
|
],
|
||||||
|
|
||||||
|
// ---------------- Classi e calendario
|
||||||
|
[
|
||||||
|
'key' => 'classes',
|
||||||
|
'phase' => 'classes',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Classi',
|
||||||
|
'text' => 'Crea le categorie (es. Hatha, Aerial) e le classi settimanali con giorno, orario, durata e posti.',
|
||||||
|
'url' => 'admin-services.php',
|
||||||
|
'cta' => 'Crea le classi',
|
||||||
|
'done' => $classes > 0,
|
||||||
|
'detail' => $classes ? $classes . ' classi' : ''
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'calendar',
|
||||||
|
'phase' => 'classes',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Calendario delle lezioni',
|
||||||
|
'text' => 'Genera le lezioni in calendario per le prossime settimane: sono quelle che le allieve prenotano.',
|
||||||
|
'url' => 'admin-services.php',
|
||||||
|
'cta' => 'Programma le lezioni',
|
||||||
|
'done' => $future > 0,
|
||||||
|
'detail' => $future ? $future . ' lezioni in calendario' : ''
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'dayoff',
|
||||||
|
'phase' => 'classes',
|
||||||
|
'required' => false,
|
||||||
|
'title' => 'Giorni di chiusura',
|
||||||
|
'text' => 'Festività e chiusure: in quei giorni non si prenota e i pacchetti non scalano lezioni.',
|
||||||
|
'url' => 'dayoff.php',
|
||||||
|
'cta' => 'Aggiungi chiusure',
|
||||||
|
'done' => $dayoffs > 0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'booking',
|
||||||
|
'phase' => 'classes',
|
||||||
|
'required' => true,
|
||||||
|
'manual' => true,
|
||||||
|
'title' => 'Regole di prenotazione',
|
||||||
|
'text' => 'Lista d\'attesa, insegnante visibile, ore minime per annullare, avviso per le allieve. Controllale e segna il passo come fatto.',
|
||||||
|
'url' => 'optionsschool.php?tab=booking',
|
||||||
|
'cta' => 'Controlla le regole',
|
||||||
|
'done' => false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'packages',
|
||||||
|
'phase' => 'classes',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Scadenza e recuperi dei pacchetti',
|
||||||
|
'text' => 'Per ogni numero di lezioni: dopo quante lezioni scade il pacchetto e quanti recuperi sono ammessi.',
|
||||||
|
'url' => 'package_rules.php',
|
||||||
|
'cta' => 'Imposta le regole',
|
||||||
|
'done' => $rules > 0,
|
||||||
|
'detail' => $rules ? $rules . ' regole' : ''
|
||||||
|
],
|
||||||
|
|
||||||
|
// ---------------- Vendita
|
||||||
|
[
|
||||||
|
'key' => 'products',
|
||||||
|
'phase' => 'sell',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Prodotti',
|
||||||
|
'text' => 'Cosa vendi: pacchetti a classe fissa, carnet, lezione di prova, tessera, buoni regalo. Con foto, prezzi e opzioni.',
|
||||||
|
'url' => 'products.php',
|
||||||
|
'cta' => 'Crea i prodotti',
|
||||||
|
'done' => $products > 0,
|
||||||
|
'detail' => $products ? $products . ' in vendita' : ''
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'payments',
|
||||||
|
'phase' => 'sell',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Pagamenti',
|
||||||
|
'text' => 'Attiva il bonifico (intestatario e IBAN) e, quando disponibile, la carta. Imposta anche le condizioni di acquisto.',
|
||||||
|
'url' => 'optionsschool.php?tab=shop',
|
||||||
|
'cta' => 'Configura i pagamenti',
|
||||||
|
'done' => $bankOk || $cardOk,
|
||||||
|
'detail' => trim(($bankOk ? 'Bonifico' : '') . ($bankOk && $cardOk ? ' · ' : '') . ($cardOk ? 'Carta' : ''))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'shop',
|
||||||
|
'phase' => 'sell',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Apri il negozio',
|
||||||
|
'text' => 'Accendi "Negozio attivo": da quel momento le allieve possono acquistare dall\'app.',
|
||||||
|
'url' => 'optionsschool.php?tab=shop',
|
||||||
|
'cta' => 'Attiva il negozio',
|
||||||
|
'done' => $shopOn
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'subscription',
|
||||||
|
'phase' => 'sell',
|
||||||
|
'required' => false,
|
||||||
|
'title' => 'Abbonamento YogiBook',
|
||||||
|
'text' => 'Controlla il tuo piano e la scadenza della prova.',
|
||||||
|
'url' => 'subscription.php',
|
||||||
|
'cta' => 'Vedi l\'abbonamento',
|
||||||
|
'done' => $sub !== null && in_array($sub['code'], ['active', 'expiring', 'exempt'], true),
|
||||||
|
'detail' => $sub ? $sub['label'] . ($sub['ends_on'] ? ' fino al ' . date('d/m/Y', strtotime($sub['ends_on'])) : '') : ''
|
||||||
|
],
|
||||||
|
|
||||||
|
// ---------------- Prova finale
|
||||||
|
[
|
||||||
|
'key' => 'test_buy',
|
||||||
|
'phase' => 'test',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Acquista come un\'allieva',
|
||||||
|
'text' => 'Dal selettore Vista in alto nel menu passa a "Allievo", apri il Negozio e compra un prodotto con bonifico. Controlla riepilogo, causale e pagina di conferma.',
|
||||||
|
'url' => 'shop.php',
|
||||||
|
'cta' => 'Apri il negozio',
|
||||||
|
'done' => $testOrder > 0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'test_confirm',
|
||||||
|
'phase' => 'test',
|
||||||
|
'required' => true,
|
||||||
|
'title' => 'Gestisci l\'ordine di prova',
|
||||||
|
'text' => 'Torna alla vista "Scuola", apri Ordini: segna il pagamento come ricevuto (e propagalo se è a classe fissa) oppure annullalo.',
|
||||||
|
'url' => 'school_orders.php',
|
||||||
|
'cta' => 'Apri gli ordini',
|
||||||
|
'done' => $testDone > 0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'test_book',
|
||||||
|
'phase' => 'test',
|
||||||
|
'required' => false,
|
||||||
|
'manual' => true,
|
||||||
|
'title' => 'Prenota e annulla una lezione',
|
||||||
|
'text' => 'Sempre come allieva, prenota una lezione dal pannello Prenotazioni e poi annullala: verifichi posti e regole di cancellazione.',
|
||||||
|
'url' => 'userpanel.php',
|
||||||
|
'cta' => 'Apri le prenotazioni',
|
||||||
|
'done' => false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'key' => 'invite',
|
||||||
|
'phase' => 'test',
|
||||||
|
'required' => false,
|
||||||
|
'manual' => true,
|
||||||
|
'title' => 'Invita le tue allieve',
|
||||||
|
'text' => 'Comunica alle allieve l\'indirizzo di YogiBook per registrarsi e scegli tu quando aprire il negozio a tutte.',
|
||||||
|
'url' => '',
|
||||||
|
'cta' => '',
|
||||||
|
'done' => $students > 0,
|
||||||
|
'detail' => $students ? $students . ' allieve iscritte' : ''
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($steps as &$s) {
|
||||||
|
$s += ['manual' => false, 'detail' => ''];
|
||||||
|
$s['auto'] = $s['done'];
|
||||||
|
$s['done'] = $s['done'] || isset($state['done'][$s['key']]);
|
||||||
|
$s['skipped'] = !$s['done'] && !$s['required'] && isset($state['skip'][$s['key']]);
|
||||||
|
}
|
||||||
|
unset($s);
|
||||||
|
return $steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** [fatti (o saltati), totale, obbligatori mancanti] */
|
||||||
|
public static function progress(array $steps): array
|
||||||
|
{
|
||||||
|
$done = 0;
|
||||||
|
$missing = 0;
|
||||||
|
foreach ($steps as $s) {
|
||||||
|
if ($s['done'] || $s['skipped']) {
|
||||||
|
$done++;
|
||||||
|
} elseif ($s['required']) {
|
||||||
|
$missing++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [$done, count($steps), $missing];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,976 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShopService
|
||||||
|
* Logica del negozio della scuola in un unico posto: catalogo, classi valide,
|
||||||
|
* posti liberi, situazione dell'allieva. Usata da:
|
||||||
|
* - shop.php (negozio dell'allieva nella webapp)
|
||||||
|
* - in seguito: checkout, API pubblica per WordPress (apiwp), app mobile
|
||||||
|
*
|
||||||
|
* Tutti i metodi ricevono $idschool esplicito: funziona anche senza sessione.
|
||||||
|
* Posti occupati = prenotazioni 'booked' + 'pending' della lezione (come BookingRules).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!class_exists('DBHandlerSelect')) {
|
||||||
|
require_once __DIR__ . '/db-functions.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShopService
|
||||||
|
{
|
||||||
|
/** Giorni di calendario considerati per i posti delle classi fisse */
|
||||||
|
const LOOKAHEAD_DAYS = 120;
|
||||||
|
/** Lezioni singole/prova acquistabili nei prossimi N giorni */
|
||||||
|
const SINGLE_DAYS = 21;
|
||||||
|
/** Massimo di lezioni future lette per ogni classe */
|
||||||
|
const MAX_OCCURRENCES = 30;
|
||||||
|
|
||||||
|
const GIORNI = ['domenica', 'lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato'];
|
||||||
|
const MESI = [1 => 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catalogo completo, pronto per json_encode (lo stesso formato servirà all'API WordPress).
|
||||||
|
*
|
||||||
|
* @param int $idschool
|
||||||
|
* @param int|null $userId allieva loggata (per prova già usata, tessera, pacchetti attivi)
|
||||||
|
* @param bool $onlineOnly true = solo prodotti "acquistabili online"
|
||||||
|
*/
|
||||||
|
public static function catalog(int $idschool, ?int $userId = null, bool $onlineOnly = true): array
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
|
||||||
|
// ---- Prodotti e opzioni
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT * FROM products WHERE idschool = ? AND active = 'Y'" . ($onlineOnly ? " AND visible_online = 'Y'" : "") . "
|
||||||
|
ORDER BY FIELD(kind, 'lessons', 'membership', 'voucher'), sort_order, title"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$rows = $st->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$variantsBy = [];
|
||||||
|
$st = $pdo->prepare("SELECT * FROM product_variants WHERE idschool = ? AND active = 'Y' ORDER BY sort_order, idvariant");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $v) {
|
||||||
|
$variantsBy[(int) $v['idproduct']][] = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
$linksBy = [];
|
||||||
|
$st = $pdo->prepare("SELECT idproduct, idservice, idservicecategory FROM product_services WHERE idschool = ?");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $l) {
|
||||||
|
$linksBy[(int) $l['idproduct']][] = $l;
|
||||||
|
}
|
||||||
|
|
||||||
|
$galleryBy = [];
|
||||||
|
$st = $pdo->prepare("SELECT idproduct, filename FROM product_images WHERE idschool = ? ORDER BY sort_order, idimage");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $g) {
|
||||||
|
$galleryBy[(int) $g['idproduct']][] = $g['filename'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$variantLabel = [];
|
||||||
|
$st = $pdo->prepare("SELECT v.idvariant, v.label, p.title FROM product_variants v JOIN products p ON p.idproduct = v.idproduct WHERE v.idschool = ?");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) {
|
||||||
|
$variantLabel[(int) $r['idvariant']] = $r['title'] . ' · ' . $r['label'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Classi della scuola
|
||||||
|
$showTeacher = SchoolSettings::get('show_teacher', 'N', $idschool) === 'Y';
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT s.idservice, s.servicename, s.day, s.time, s.category, s.maxcapacity, s.colorclass, s.classduration,
|
||||||
|
TRIM(CONCAT(COALESCE(em.nameemployee, ''), ' ', COALESCE(em.surnameemployee, ''))) AS teacher
|
||||||
|
FROM service s
|
||||||
|
LEFT JOIN employee em ON em.idemployee = s.idteacher AND em.idschool = s.idschool
|
||||||
|
WHERE s.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$servicesAll = [];
|
||||||
|
$byCategory = [];
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $s) {
|
||||||
|
$servicesAll[(int) $s['idservice']] = $s;
|
||||||
|
$byCategory[(int) $s['category']][] = (int) $s['idservice'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT idservicecategory, namecategory FROM servicecategory WHERE idschool = ? ORDER BY namecategory");
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
$catNames = [];
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $c) {
|
||||||
|
$catNames[(int) $c['idservicecategory']] = $c['namecategory'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Situazione dell'allieva
|
||||||
|
$user = self::userContext($idschool, $userId);
|
||||||
|
|
||||||
|
// ---- Costruzione prodotti
|
||||||
|
$products = [];
|
||||||
|
$usedSvcs = [];
|
||||||
|
$usedCats = [];
|
||||||
|
foreach ($rows as $p) {
|
||||||
|
$pid = (int) $p['idproduct'];
|
||||||
|
if (empty($variantsBy[$pid])) {
|
||||||
|
continue; // nessuna opzione attiva = non acquistabile
|
||||||
|
}
|
||||||
|
$svc = [];
|
||||||
|
foreach ($linksBy[$pid] ?? [] as $l) {
|
||||||
|
if (!empty($l['idservice']) && isset($servicesAll[(int) $l['idservice']])) {
|
||||||
|
$svc[] = (int) $l['idservice'];
|
||||||
|
}
|
||||||
|
if (!empty($l['idservicecategory'])) {
|
||||||
|
$svc = array_merge($svc, $byCategory[(int) $l['idservicecategory']] ?? []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$svc = array_values(array_unique($svc));
|
||||||
|
if ($p['kind'] === 'lessons' && !$svc) {
|
||||||
|
continue; // pacchetto senza classi: non vendibile
|
||||||
|
}
|
||||||
|
|
||||||
|
$cats = [];
|
||||||
|
foreach ($svc as $sid) {
|
||||||
|
$cid = (int) $servicesAll[$sid]['category'];
|
||||||
|
if (isset($catNames[$cid])) {
|
||||||
|
$cats[$cid] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$cats = array_keys($cats);
|
||||||
|
if ($p['kind'] === 'lessons') {
|
||||||
|
$usedSvcs = array_merge($usedSvcs, $svc);
|
||||||
|
$usedCats = array_merge($usedCats, $cats);
|
||||||
|
}
|
||||||
|
|
||||||
|
$variants = [];
|
||||||
|
foreach ($variantsBy[$pid] as $v) {
|
||||||
|
$variants[] = [
|
||||||
|
'id' => (int) $v['idvariant'],
|
||||||
|
'label' => $v['label'],
|
||||||
|
'lessons' => $v['lessons'] !== null ? (int) $v['lessons'] : null,
|
||||||
|
'price' => (float) $v['price'],
|
||||||
|
'compare' => $v['compare_price'] !== null ? (float) $v['compare_price'] : null,
|
||||||
|
'note' => $v['price_note'],
|
||||||
|
'vmode' => $v['validity_mode'],
|
||||||
|
'vvalue' => $v['validity_value'] !== null ? (int) $v['validity_value'] : null,
|
||||||
|
'vunit' => $v['validity_unit'],
|
||||||
|
'vstart' => $v['validity_start'],
|
||||||
|
'target' => $v['target_idvariant'] !== null ? (int) $v['target_idvariant'] : null,
|
||||||
|
'targetLabel' => $v['target_idvariant'] !== null ? ($variantLabel[(int) $v['target_idvariant']] ?? '') : '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$mode = $p['kind'] === 'lessons' ? $p['booking_mode'] : $p['kind'];
|
||||||
|
$products[] = [
|
||||||
|
'id' => $pid,
|
||||||
|
'slug' => $p['slug'],
|
||||||
|
'kind' => $p['kind'],
|
||||||
|
'mode' => $mode, // fixed | free | single | membership | voucher
|
||||||
|
'group' => self::group($p), // per i filtri del catalogo
|
||||||
|
'slots' => (int) $p['fixed_slots'],
|
||||||
|
'weekly' => $p['weekly_limit'] !== null ? (int) $p['weekly_limit'] : null,
|
||||||
|
'maxres' => $p['max_reschedule'] !== null ? (int) $p['max_reschedule'] : null,
|
||||||
|
'once' => $p['once_per_student'] === 'Y',
|
||||||
|
'title' => $p['title'],
|
||||||
|
'subtitle' => (string) $p['subtitle'],
|
||||||
|
'badge' => (string) $p['badge'],
|
||||||
|
'cover' => (string) $p['cover_image'],
|
||||||
|
'gallery' => $galleryBy[$pid] ?? [],
|
||||||
|
'description' => (string) $p['description'], // HTML già ripulito al salvataggio
|
||||||
|
'suitable' => (string) $p['suitable_for'],
|
||||||
|
'requirements' => (string) $p['requirements'],
|
||||||
|
'pros' => self::lines($p['pros']),
|
||||||
|
'cons' => self::lines($p['cons']),
|
||||||
|
'services' => $svc,
|
||||||
|
'cats' => $cats,
|
||||||
|
'variants' => $variants,
|
||||||
|
'blocked' => ($p['once_per_student'] === 'Y' && in_array($pid, $user['usedProducts'], true)) ? 'used' : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Calendario e posti delle classi usate dai pacchetti
|
||||||
|
$services = self::servicesWithOccurrences($idschool, array_values(array_unique($usedSvcs)), $servicesAll, $showTeacher, $userId);
|
||||||
|
|
||||||
|
// ---- Discipline (categorie) presenti nel catalogo
|
||||||
|
$categories = [];
|
||||||
|
foreach (array_unique($usedCats) as $cid) {
|
||||||
|
$categories[] = ['id' => $cid, 'name' => $catNames[$cid]];
|
||||||
|
}
|
||||||
|
usort($categories, fn($a, $b) => strcasecmp($a['name'], $b['name']));
|
||||||
|
|
||||||
|
// ---- Date utili (tessere)
|
||||||
|
$seasonStart = max(1, min(12, (int) SchoolSettings::get('membership_season_start', 9, $idschool)));
|
||||||
|
$today = new DateTimeImmutable('today');
|
||||||
|
$y = (int) $today->format('Y');
|
||||||
|
$endYear = ((int) $today->format('n') >= $seasonStart) ? $y + 1 : $y;
|
||||||
|
$seasonEnd = (new DateTimeImmutable(sprintf('%04d-%02d-01', $endYear, $seasonStart)))->modify('-1 day');
|
||||||
|
|
||||||
|
// Prodotto tessera da proporre se serve
|
||||||
|
$user['membershipProduct'] = null;
|
||||||
|
foreach ($products as $p) {
|
||||||
|
if ($p['kind'] === 'membership') {
|
||||||
|
$user['membershipProduct'] = $p['id'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($user['usedProducts']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'today' => $today->format('Y-m-d'),
|
||||||
|
'yearEnd' => $y . '-12-31',
|
||||||
|
'seasonEnd' => $seasonEnd->format('Y-m-d'),
|
||||||
|
'singleDays' => self::SINGLE_DAYS,
|
||||||
|
'products' => $products,
|
||||||
|
'services' => (object) $services,
|
||||||
|
'categories' => $categories,
|
||||||
|
'user' => $user,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gruppo del catalogo: single | fixed | free | membership | voucher */
|
||||||
|
public static function group(array $p): string
|
||||||
|
{
|
||||||
|
return $p['kind'] === 'lessons' ? (string) $p['booking_mode'] : (string) $p['kind'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Situazione dell'allieva nella scuola: prodotti "una volta" già acquistati,
|
||||||
|
* tessera valida, pacchetti attivi.
|
||||||
|
*/
|
||||||
|
public static function userContext(int $idschool, ?int $userId): array
|
||||||
|
{
|
||||||
|
$required = SchoolSettings::get('membership_required', 'N', $idschool) === 'Y';
|
||||||
|
$ctx = [
|
||||||
|
'logged' => (bool) $userId,
|
||||||
|
'membershipRequired' => $required,
|
||||||
|
'hasMembership' => false,
|
||||||
|
'membershipUntil' => null,
|
||||||
|
'packages' => [],
|
||||||
|
'usedProducts' => [],
|
||||||
|
];
|
||||||
|
if (!$userId) {
|
||||||
|
return $ctx;
|
||||||
|
}
|
||||||
|
$pdo = self::pdo();
|
||||||
|
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT DISTINCT idproduct FROM orderbook
|
||||||
|
WHERE iduser = ? AND idschool = ? AND idproduct IS NOT NULL
|
||||||
|
AND (payment_status IS NULL OR payment_status NOT IN ('cancelled', 'refunded'))"
|
||||||
|
);
|
||||||
|
$st->execute([$userId, $idschool]);
|
||||||
|
$ctx['usedProducts'] = array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN));
|
||||||
|
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT MAX(valid_to) FROM memberships
|
||||||
|
WHERE iduser = ? AND idschool = ? AND status = 'active' AND valid_from <= CURDATE() AND valid_to >= CURDATE()"
|
||||||
|
);
|
||||||
|
$st->execute([$userId, $idschool]);
|
||||||
|
$until = $st->fetchColumn();
|
||||||
|
$ctx['hasMembership'] = (bool) $until;
|
||||||
|
$ctx['membershipUntil'] = $until ?: null;
|
||||||
|
|
||||||
|
// Pacchetti attivi: non scaduti e con lezioni rimaste
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT ob.idorderbook, ob.product_name, ob.nticket, ob.quantityclass, ob.expireon, ob.payment_status,
|
||||||
|
s.servicename,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b
|
||||||
|
WHERE b.idorder = ob.idorderbook AND b.idschool = ob.idschool
|
||||||
|
AND b.status <> 'cancelled' AND b.is_gift = 'N') AS used
|
||||||
|
FROM orderbook ob
|
||||||
|
LEFT JOIN service s ON s.idservice = ob.idservice
|
||||||
|
WHERE ob.iduser = ? AND ob.idschool = ?
|
||||||
|
AND (ob.expireon IS NULL OR ob.expireon >= CURDATE())
|
||||||
|
AND (ob.payment_status IS NULL OR ob.payment_status NOT IN ('cancelled', 'refunded'))
|
||||||
|
ORDER BY ob.expireon IS NULL, ob.expireon"
|
||||||
|
);
|
||||||
|
$st->execute([$userId, $idschool]);
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $o) {
|
||||||
|
$tot = (int) $o['nticket'] > 0 ? (int) $o['nticket'] : (int) $o['quantityclass'];
|
||||||
|
$left = $tot > 0 ? max(0, $tot - (int) $o['used']) : null;
|
||||||
|
if ($left === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ctx['packages'][] = [
|
||||||
|
'title' => (string) ($o['product_name'] ?: $o['servicename'] ?: 'Pacchetto'),
|
||||||
|
'left' => $left,
|
||||||
|
'expire' => $o['expireon'],
|
||||||
|
'pending' => $o['payment_status'] === 'pending',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lezioni future delle classi indicate, con posti liberi.
|
||||||
|
* @return array idservice => [name, day, teacher, cap, cat, occ => [[id, date, time, label, free, mine]]]
|
||||||
|
*/
|
||||||
|
public static function servicesWithOccurrences(int $idschool, array $ids, array $servicesAll, bool $showTeacher, ?int $userId = null): array
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
foreach ($ids as $sid) {
|
||||||
|
if (!isset($servicesAll[$sid])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$s = $servicesAll[$sid];
|
||||||
|
$out[$sid] = [
|
||||||
|
'name' => $s['servicename'],
|
||||||
|
'day' => trim($s['day'] . ' ' . $s['time']),
|
||||||
|
'teacher' => $showTeacher ? trim((string) $s['teacher']) : '',
|
||||||
|
'cap' => ($s['maxcapacity'] !== null && (int) $s['maxcapacity'] > 0) ? (int) $s['maxcapacity'] : null,
|
||||||
|
'cat' => (int) $s['category'],
|
||||||
|
'color' => preg_match('/^#[0-9a-fA-F]{6}$/', (string) ($s['colorclass'] ?? '')) ? strtolower($s['colorclass']) : null,
|
||||||
|
'minutes' => (int) round((float) ($s['classduration'] ?? 0) * ((float) ($s['classduration'] ?? 0) <= 5 ? 60 : 1)),
|
||||||
|
'occ' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!$out) {
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ph = implode(',', array_fill(0, count($out), '?'));
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT ss.idserviceschedule, ss.idservice, ss.dateschedule,
|
||||||
|
(SELECT COUNT(*) FROM bookingclass b
|
||||||
|
WHERE b.idserviceschedule = ss.idserviceschedule AND b.idschool = ss.idschool
|
||||||
|
AND b.status IN ('booked', 'pending')) AS taken
|
||||||
|
" . ($userId ? ", (SELECT COUNT(*) FROM bookingclass b2
|
||||||
|
WHERE b2.idserviceschedule = ss.idserviceschedule AND b2.idschool = ss.idschool
|
||||||
|
AND b2.iduser = ? AND b2.status <> 'cancelled') AS mine" : ", 0 AS mine") . "
|
||||||
|
FROM serviceschedule ss
|
||||||
|
WHERE ss.idschool = ?
|
||||||
|
AND ss.idservice IN ($ph)
|
||||||
|
AND ss.dateschedule > NOW()
|
||||||
|
AND ss.dateschedule < CURDATE() + INTERVAL " . (int) self::LOOKAHEAD_DAYS . " DAY
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM dayoff d WHERE d.idschool = ss.idschool AND d.dayoffdate = DATE(ss.dateschedule))
|
||||||
|
ORDER BY ss.dateschedule"
|
||||||
|
);
|
||||||
|
$args = $userId ? [$userId, $idschool] : [$idschool];
|
||||||
|
$st->execute(array_merge($args, array_keys($out)));
|
||||||
|
|
||||||
|
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $o) {
|
||||||
|
$sid = (int) $o['idservice'];
|
||||||
|
if (count($out[$sid]['occ']) >= self::MAX_OCCURRENCES) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ts = strtotime($o['dateschedule']);
|
||||||
|
$cap = $out[$sid]['cap'];
|
||||||
|
$out[$sid]['occ'][] = [
|
||||||
|
'id' => (int) $o['idserviceschedule'],
|
||||||
|
'date' => date('Y-m-d', $ts),
|
||||||
|
'time' => date('H:i', $ts),
|
||||||
|
'label' => self::dateLabel($ts),
|
||||||
|
'free' => $cap === null ? null : max(0, $cap - (int) $o['taken']),
|
||||||
|
'mine' => (int) $o['mine'] > 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** "Martedì 13 ottobre · 18:00" */
|
||||||
|
public static function dateLabel(int $ts): string
|
||||||
|
{
|
||||||
|
return ucfirst(self::GIORNI[(int) date('w', $ts)]) . ' ' . date('j', $ts) . ' ' . self::MESI[(int) date('n', $ts)] . ' · ' . date('H:i', $ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function lines(?string $t): array
|
||||||
|
{
|
||||||
|
return array_values(array_filter(array_map('trim', preg_split('/\r\n|\r|\n/', (string) $t))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================
|
||||||
|
* CHECKOUT
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
/** Metodi di pagamento attivi per la scuola */
|
||||||
|
public static function paymentMethods(int $idschool): array
|
||||||
|
{
|
||||||
|
$bank = SchoolSettings::get('bank_enabled', 'N', $idschool) === 'Y'
|
||||||
|
&& trim((string) SchoolSettings::get('bank_holder', '', $idschool)) !== ''
|
||||||
|
&& trim((string) SchoolSettings::get('bank_iban', '', $idschool)) !== '';
|
||||||
|
// La carta arriverà con il collegamento Stripe Connect della scuola
|
||||||
|
$card = SchoolSettings::get('stripe_charges_enabled', 'N', $idschool) === 'Y'
|
||||||
|
&& trim((string) SchoolSettings::get('stripe_account_id', '', $idschool)) !== '';
|
||||||
|
return ['bank' => $bank, 'card' => $card];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ricontrolla lato server la scelta arrivata dal negozio.
|
||||||
|
* $in: idvariant, services (array di idservice), idschedule, recipient_name, recipient_email, recipient_message
|
||||||
|
* @return array product, variant, services, schedule, recipient
|
||||||
|
* @throws RuntimeException con messaggio per l'allieva
|
||||||
|
*/
|
||||||
|
public static function selection(int $idschool, int $userId, array $in): array
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT v.*, p.kind, p.title, p.booking_mode, p.fixed_slots, p.weekly_limit, p.max_reschedule,
|
||||||
|
p.once_per_student, p.active AS p_active, p.visible_online, p.slug
|
||||||
|
FROM product_variants v
|
||||||
|
JOIN products p ON p.idproduct = v.idproduct AND p.idschool = v.idschool
|
||||||
|
WHERE v.idvariant = ? AND v.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([(int) ($in['idvariant'] ?? 0), $idschool]);
|
||||||
|
$row = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$row || $row['active'] !== 'Y' || $row['p_active'] !== 'Y' || $row['visible_online'] !== 'Y') {
|
||||||
|
throw new RuntimeException('Questo prodotto non è più disponibile.');
|
||||||
|
}
|
||||||
|
$pid = (int) $row['idproduct'];
|
||||||
|
$mode = $row['kind'] === 'lessons' ? $row['booking_mode'] : $row['kind'];
|
||||||
|
|
||||||
|
if ($row['once_per_student'] === 'Y') {
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT 1 FROM orderbook WHERE iduser = ? AND idschool = ? AND idproduct = ?
|
||||||
|
AND (payment_status IS NULL OR payment_status NOT IN ('cancelled', 'refunded')) LIMIT 1"
|
||||||
|
);
|
||||||
|
$st->execute([$userId, $idschool, $pid]);
|
||||||
|
if ($st->fetchColumn()) {
|
||||||
|
throw new RuntimeException('Hai già utilizzato questo prodotto: si può acquistare una sola volta.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed = self::productServiceIds($idschool, $pid);
|
||||||
|
$sel = [
|
||||||
|
'product' => $row,
|
||||||
|
'mode' => $mode,
|
||||||
|
'variant' => $row,
|
||||||
|
'services' => [],
|
||||||
|
'schedule' => null,
|
||||||
|
'recipient' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($mode === 'fixed') {
|
||||||
|
$slots = (int) $row['fixed_slots'] === 2 ? 2 : 1;
|
||||||
|
$ids = array_values(array_unique(array_filter(array_map('intval', (array) ($in['services'] ?? [])))));
|
||||||
|
if (count($ids) !== $slots) {
|
||||||
|
throw new RuntimeException($slots === 2 ? 'Scegli le tue due classi.' : 'Scegli la tua classe.');
|
||||||
|
}
|
||||||
|
$weeks = $row['lessons'] ? (int) ceil((int) $row['lessons'] / $slots) : 8;
|
||||||
|
foreach ($ids as $sid) {
|
||||||
|
if (!in_array($sid, $allowed, true)) {
|
||||||
|
throw new RuntimeException('Una delle classi scelte non è inclusa in questo prodotto.');
|
||||||
|
}
|
||||||
|
$free = self::fixedFree($idschool, $sid, $weeks);
|
||||||
|
if ($free === -1) {
|
||||||
|
throw new RuntimeException('Una delle classi scelte non ha lezioni in calendario.');
|
||||||
|
}
|
||||||
|
if ($free === 0) {
|
||||||
|
throw new RuntimeException('Una delle classi scelte è al completo. Torna indietro e scegline un\'altra.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sel['services'] = $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === 'single') {
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT ss.*, s.servicename, s.maxcapacity FROM serviceschedule ss
|
||||||
|
JOIN service s ON s.idservice = ss.idservice
|
||||||
|
WHERE ss.idserviceschedule = ? AND ss.idschool = ? AND ss.dateschedule > NOW()"
|
||||||
|
);
|
||||||
|
$st->execute([(int) ($in['idschedule'] ?? 0), $idschool]);
|
||||||
|
$sch = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$sch || !in_array((int) $sch['idservice'], $allowed, true)) {
|
||||||
|
throw new RuntimeException('La lezione scelta non è più disponibile.');
|
||||||
|
}
|
||||||
|
$st = $pdo->prepare("SELECT 1 FROM bookingclass WHERE idserviceschedule = ? AND iduser = ? AND idschool = ? AND status <> 'cancelled' LIMIT 1");
|
||||||
|
$st->execute([(int) $sch['idserviceschedule'], $userId, $idschool]);
|
||||||
|
if ($st->fetchColumn()) {
|
||||||
|
throw new RuntimeException('Sei già iscritta a questa lezione.');
|
||||||
|
}
|
||||||
|
if ((int) $sch['maxcapacity'] > 0 && self::occupied($idschool, (int) $sch['idserviceschedule']) >= (int) $sch['maxcapacity']) {
|
||||||
|
throw new RuntimeException('La lezione scelta è al completo. Torna indietro e scegli un\'altra data.');
|
||||||
|
}
|
||||||
|
$sel['schedule'] = $sch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === 'voucher') {
|
||||||
|
$name = trim((string) ($in['recipient_name'] ?? ''));
|
||||||
|
$email = trim((string) ($in['recipient_email'] ?? ''));
|
||||||
|
if ($name === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
throw new RuntimeException('Indica nome ed email di chi riceve il buono.');
|
||||||
|
}
|
||||||
|
if (empty($row['target_idvariant'])) {
|
||||||
|
throw new RuntimeException('Questo buono non è configurato correttamente. Contatta la scuola.');
|
||||||
|
}
|
||||||
|
$sel['recipient'] = [
|
||||||
|
'name' => mb_substr($name, 0, 191),
|
||||||
|
'email' => mb_substr($email, 0, 191),
|
||||||
|
'message' => mb_substr(trim((string) ($in['recipient_message'] ?? '')), 0, 500),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $sel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** idservice validi per un prodotto (classi singole + categorie intere) */
|
||||||
|
public static function productServiceIds(int $idschool, int $idproduct): array
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT DISTINCT s.idservice
|
||||||
|
FROM product_services ps
|
||||||
|
JOIN service s ON s.idschool = ps.idschool
|
||||||
|
AND (s.idservice = ps.idservice OR (ps.idservicecategory IS NOT NULL AND s.category = ps.idservicecategory))
|
||||||
|
WHERE ps.idproduct = ? AND ps.idschool = ?"
|
||||||
|
);
|
||||||
|
$st->execute([$idproduct, $idschool]);
|
||||||
|
return array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function occupied(int $idschool, int $idschedule): int
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT COUNT(*) FROM bookingclass WHERE idserviceschedule = ? AND idschool = ? AND status IN ('booked', 'pending')"
|
||||||
|
);
|
||||||
|
$st->execute([$idschedule, $idschool]);
|
||||||
|
return (int) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posti liberi minimi sulle prossime $weeks lezioni di una classe.
|
||||||
|
* null = senza limite, -1 = nessuna lezione in calendario
|
||||||
|
*/
|
||||||
|
public static function fixedFree(int $idschool, int $idservice, int $weeks): ?int
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$st = $pdo->prepare("SELECT maxcapacity FROM service WHERE idservice = ? AND idschool = ?");
|
||||||
|
$st->execute([$idservice, $idschool]);
|
||||||
|
$cap = (int) $st->fetchColumn();
|
||||||
|
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT (SELECT COUNT(*) FROM bookingclass b WHERE b.idserviceschedule = ss.idserviceschedule
|
||||||
|
AND b.idschool = ss.idschool AND b.status IN ('booked', 'pending')) AS taken
|
||||||
|
FROM serviceschedule ss
|
||||||
|
WHERE ss.idservice = ? AND ss.idschool = ? AND ss.dateschedule > NOW()
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM dayoff d WHERE d.idschool = ss.idschool AND d.dayoffdate = DATE(ss.dateschedule))
|
||||||
|
ORDER BY ss.dateschedule
|
||||||
|
LIMIT " . max(1, $weeks)
|
||||||
|
);
|
||||||
|
$st->execute([$idservice, $idschool]);
|
||||||
|
$taken = array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN));
|
||||||
|
if (!$taken) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return $cap > 0 ? max(0, $cap - max($taken)) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica un codice sconto per l'opzione scelta (l'utente è sempre quello della sessione).
|
||||||
|
* @return array idcoupon, code, discount
|
||||||
|
* @throws RuntimeException
|
||||||
|
*/
|
||||||
|
public static function checkCoupon(int $idschool, int $userId, string $code, array $variant): array
|
||||||
|
{
|
||||||
|
$code = strtoupper(trim($code));
|
||||||
|
$price = (float) $variant['price'];
|
||||||
|
$pdo = self::pdo();
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT * FROM coupons WHERE idschool = ? AND code = ? AND active = 'Y' LIMIT 1");
|
||||||
|
$st->execute([$idschool, $code]);
|
||||||
|
$c = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$today = date('Y-m-d');
|
||||||
|
if (!$c || ($c['valid_from'] && $today < $c['valid_from']) || ($c['valid_to'] && $today > $c['valid_to'])) {
|
||||||
|
throw new RuntimeException('Codice non valido o scaduto.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT idproduct, idvariant FROM coupon_products WHERE idcoupon = ? AND idschool = ?");
|
||||||
|
$st->execute([(int) $c['idcoupon'], $idschool]);
|
||||||
|
$limits = $st->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
if ($limits) {
|
||||||
|
$ok = false;
|
||||||
|
foreach ($limits as $l) {
|
||||||
|
if (
|
||||||
|
(int) $l['idvariant'] === (int) $variant['idvariant']
|
||||||
|
|| ((int) $l['idproduct'] === (int) $variant['idproduct'] && empty($l['idvariant']))
|
||||||
|
) {
|
||||||
|
$ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$ok) {
|
||||||
|
throw new RuntimeException('Questo codice non vale su questo prodotto.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($c['min_amount'] !== null && $price < (float) $c['min_amount']) {
|
||||||
|
throw new RuntimeException('Codice valido per acquisti da ' . number_format((float) $c['min_amount'], 2, ',', '.') . ' €.');
|
||||||
|
}
|
||||||
|
if ($c['max_uses'] !== null) {
|
||||||
|
$st = $pdo->prepare("SELECT COUNT(*) FROM coupon_redemptions WHERE idcoupon = ? AND idschool = ?");
|
||||||
|
$st->execute([(int) $c['idcoupon'], $idschool]);
|
||||||
|
if ((int) $st->fetchColumn() >= (int) $c['max_uses']) {
|
||||||
|
throw new RuntimeException('Codice esaurito.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($c['max_uses_per_user'] !== null) {
|
||||||
|
$st = $pdo->prepare("SELECT COUNT(*) FROM coupon_redemptions WHERE idcoupon = ? AND idschool = ? AND iduser = ?");
|
||||||
|
$st->execute([(int) $c['idcoupon'], $idschool, $userId]);
|
||||||
|
if ((int) $st->fetchColumn() >= (int) $c['max_uses_per_user']) {
|
||||||
|
throw new RuntimeException('Hai già usato questo codice.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($c['new_students_only'] === 'Y') {
|
||||||
|
$st = $pdo->prepare("SELECT COUNT(*) FROM orderbook WHERE iduser = ? AND idschool = ?");
|
||||||
|
$st->execute([$userId, $idschool]);
|
||||||
|
if ((int) $st->fetchColumn() > 0) {
|
||||||
|
throw new RuntimeException('Codice riservato alle nuove allieve.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$value = (float) $c['discount_value'];
|
||||||
|
$discount = $c['discount_type'] === 'fixed' ? min($value, $price) : round($price * min($value, 100) / 100, 2);
|
||||||
|
return ['idcoupon' => (int) $c['idcoupon'], 'code' => $c['code'], 'discount' => $discount];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scadenza della tessera per un'opzione (Y-m-d o null) */
|
||||||
|
public static function membershipEnd(int $idschool, array $variant, ?string $from = null): ?string
|
||||||
|
{
|
||||||
|
$from = $from ?? date('Y-m-d');
|
||||||
|
if ($variant['validity_mode'] === 'calendar_year') {
|
||||||
|
return substr($from, 0, 4) . '-12-31';
|
||||||
|
}
|
||||||
|
if ($variant['validity_mode'] === 'season') {
|
||||||
|
$start = max(1, min(12, (int) SchoolSettings::get('membership_season_start', 9, $idschool)));
|
||||||
|
$y = (int) substr($from, 0, 4);
|
||||||
|
$endYear = ((int) substr($from, 5, 2) >= $start) ? $y + 1 : $y;
|
||||||
|
return (new DateTimeImmutable(sprintf('%04d-%02d-01', $endYear, $start)))->modify('-1 day')->format('Y-m-d');
|
||||||
|
}
|
||||||
|
if (!empty($variant['validity_value'])) {
|
||||||
|
return self::addPeriod($from, (int) $variant['validity_value'], (string) $variant['validity_unit'])->modify('-1 day')->format('Y-m-d');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function addPeriod(string $from, int $n, string $unit): DateTimeImmutable
|
||||||
|
{
|
||||||
|
$d = new DateTimeImmutable($from);
|
||||||
|
if ($unit === 'days') {
|
||||||
|
return $d->modify('+' . $n . ' days');
|
||||||
|
}
|
||||||
|
if ($unit === 'weeks') {
|
||||||
|
return $d->modify('+' . ($n * 7) . ' days');
|
||||||
|
}
|
||||||
|
// mesi senza sforare (31 gennaio + 1 mese = fine febbraio)
|
||||||
|
$y = (int) $d->format('Y');
|
||||||
|
$m = (int) $d->format('n') + $n;
|
||||||
|
$y += intdiv($m - 1, 12);
|
||||||
|
$m = (($m - 1) % 12) + 1;
|
||||||
|
$last = (int) (new DateTimeImmutable(sprintf('%04d-%02d-01', $y, $m)))->format('t');
|
||||||
|
return $d->setDate($y, $m, min((int) $d->format('j'), $last));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea l'ordine (orderbook) e tutto ciò che ne deriva, in un'unica transazione.
|
||||||
|
* - classe fissa: orderbook_services (le prenotazioni le crea la scuola alla propagazione)
|
||||||
|
* - lezione singola: prenotazione subito (bonifico = 'pending', carta = 'booked')
|
||||||
|
* - buono regalo: gift_vouchers in attesa del pagamento
|
||||||
|
* - tessera: la riga in memberships nasce alla conferma del pagamento
|
||||||
|
* @param string $method 'bank' | 'stripe'
|
||||||
|
* @return int idorderbook
|
||||||
|
*/
|
||||||
|
public static function createOrder(int $idschool, int $userId, array $sel, string $method, ?array $coupon): int
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$p = $sel['product'];
|
||||||
|
$v = $sel['variant'];
|
||||||
|
$mode = $sel['mode'];
|
||||||
|
$paid = $method === 'stripe';
|
||||||
|
|
||||||
|
$st = $pdo->prepare("SELECT first_name, last_name, email FROM auth_users WHERE id = ?");
|
||||||
|
$st->execute([$userId]);
|
||||||
|
$u = $st->fetch(PDO::FETCH_ASSOC) ?: ['first_name' => '', 'last_name' => '', 'email' => ''];
|
||||||
|
|
||||||
|
$price = round((float) $v['price'], 2);
|
||||||
|
$discount = $coupon ? min(round((float) $coupon['discount'], 2), $price) : 0.0;
|
||||||
|
$total = round($price - $discount, 2);
|
||||||
|
$lessons = $v['lessons'] !== null ? (int) $v['lessons'] : null;
|
||||||
|
$today = date('Y-m-d');
|
||||||
|
|
||||||
|
// Scadenza
|
||||||
|
$expire = null;
|
||||||
|
if ($mode === 'free' && $v['validity_mode'] === 'duration' && $v['validity_value'] && $v['validity_start'] === 'purchase') {
|
||||||
|
$expire = self::addPeriod($today, (int) $v['validity_value'], (string) $v['validity_unit'])->format('Y-m-d');
|
||||||
|
} elseif ($mode === 'single' && $sel['schedule']) {
|
||||||
|
$expire = substr($sel['schedule']['dateschedule'], 0, 10);
|
||||||
|
} elseif ($mode === 'membership') {
|
||||||
|
$expire = self::membershipEnd($idschool, $v, $today);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recuperi: dal prodotto, altrimenti dai parametri della scuola per quel numero di lezioni
|
||||||
|
$maxres = $p['max_reschedule'] !== null ? (int) $p['max_reschedule'] : null;
|
||||||
|
if ($maxres === null && $lessons && in_array($mode, ['fixed', 'free'], true)) {
|
||||||
|
$st = $pdo->prepare("SELECT reschedulenumber FROM expiryparameter WHERE quantityclass = ? AND idschool = ? LIMIT 1");
|
||||||
|
$st->execute([$lessons, $idschool]);
|
||||||
|
$r = $st->fetchColumn();
|
||||||
|
$maxres = $r !== false ? (int) $r : null;
|
||||||
|
}
|
||||||
|
if ($mode === 'single') {
|
||||||
|
$maxres = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$idservice = null;
|
||||||
|
if ($mode === 'fixed') {
|
||||||
|
$idservice = $sel['services'][0];
|
||||||
|
} elseif ($mode === 'single') {
|
||||||
|
$idservice = (int) $sel['schedule']['idservice'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$snapshot = [
|
||||||
|
'mode' => $mode,
|
||||||
|
'fixed_slots' => (int) $p['fixed_slots'],
|
||||||
|
'weekly_limit' => $p['weekly_limit'] !== null ? (int) $p['weekly_limit'] : null,
|
||||||
|
'max_reschedule' => $maxres,
|
||||||
|
'lessons' => $lessons,
|
||||||
|
'validity_mode' => $v['validity_mode'],
|
||||||
|
'validity_value' => $v['validity_value'] !== null ? (int) $v['validity_value'] : null,
|
||||||
|
'validity_unit' => $v['validity_unit'],
|
||||||
|
'validity_start' => $v['validity_start'],
|
||||||
|
'services' => $mode === 'free' || $mode === 'single' ? self::productServiceIds($idschool, (int) $p['idproduct']) : $sel['services'],
|
||||||
|
'price' => $price,
|
||||||
|
];
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
// Lezione singola: blocca la riga della lezione e ricontrolla il posto
|
||||||
|
if ($mode === 'single') {
|
||||||
|
$st = $pdo->prepare("SELECT ss.idserviceschedule, s.maxcapacity FROM serviceschedule ss JOIN service s ON s.idservice = ss.idservice WHERE ss.idserviceschedule = ? AND ss.idschool = ? FOR UPDATE");
|
||||||
|
$st->execute([(int) $sel['schedule']['idserviceschedule'], $idschool]);
|
||||||
|
$lock = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$lock || ((int) $lock['maxcapacity'] > 0 && self::occupied($idschool, (int) $lock['idserviceschedule']) >= (int) $lock['maxcapacity'])) {
|
||||||
|
throw new RuntimeException('Nel frattempo la lezione si è riempita. Scegli un\'altra data.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->prepare(
|
||||||
|
"INSERT INTO orderbook
|
||||||
|
(order_date_created, order_billing_email, order_total, product_name, line_total, quantity,
|
||||||
|
idservice, is_openflexy, iduser, nticket, expireon, status, quantityclass,
|
||||||
|
first_name, last_name, maxreschedule, reprogrammed, idschool,
|
||||||
|
idproduct, idvariant, booking_mode, weekly_limit, rules_snapshot, source, payment_status,
|
||||||
|
amount, discount_amount, idcoupon)
|
||||||
|
VALUES (?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
|
)->execute([
|
||||||
|
$today,
|
||||||
|
$u['email'],
|
||||||
|
number_format($total, 2, '.', ''),
|
||||||
|
mb_substr($p['title'] . ' · ' . $v['label'], 0, 200),
|
||||||
|
number_format($total, 2, '.', ''),
|
||||||
|
$idservice,
|
||||||
|
$mode === 'free' ? 'Y' : 'N',
|
||||||
|
$userId,
|
||||||
|
$lessons,
|
||||||
|
$expire,
|
||||||
|
$paid ? ($mode === 'fixed' ? 'pending' : 'completed') : 'on-hold',
|
||||||
|
$lessons,
|
||||||
|
$u['first_name'],
|
||||||
|
$u['last_name'],
|
||||||
|
$maxres,
|
||||||
|
$idschool,
|
||||||
|
(int) $p['idproduct'],
|
||||||
|
(int) $v['idvariant'],
|
||||||
|
in_array($mode, ['fixed', 'free', 'single'], true) ? $mode : null,
|
||||||
|
$p['weekly_limit'] !== null ? (int) $p['weekly_limit'] : null,
|
||||||
|
json_encode($snapshot, JSON_UNESCAPED_UNICODE),
|
||||||
|
$method,
|
||||||
|
$paid ? 'paid' : 'pending',
|
||||||
|
$total,
|
||||||
|
$discount > 0 ? $discount : null,
|
||||||
|
$coupon ? (int) $coupon['idcoupon'] : null,
|
||||||
|
]);
|
||||||
|
$idorder = (int) $pdo->lastInsertId();
|
||||||
|
|
||||||
|
if ($mode === 'fixed') {
|
||||||
|
$ins = $pdo->prepare("INSERT INTO orderbook_services (idorderbook, idschool, idservice, slot) VALUES (?, ?, ?, ?)");
|
||||||
|
foreach ($sel['services'] as $i => $sid) {
|
||||||
|
$ins->execute([$idorder, $idschool, $sid, $i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === 'single') {
|
||||||
|
$pdo->prepare(
|
||||||
|
"INSERT INTO bookingclass (idserviceschedule, bookingstart, status, idservice, iduser, idorder, cancellation_token, idschool)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
|
)->execute([
|
||||||
|
(int) $sel['schedule']['idserviceschedule'],
|
||||||
|
$sel['schedule']['dateschedule'],
|
||||||
|
$paid ? 'booked' : 'pending',
|
||||||
|
(int) $sel['schedule']['idservice'],
|
||||||
|
$userId,
|
||||||
|
$idorder,
|
||||||
|
bin2hex(random_bytes(16)),
|
||||||
|
$idschool,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === 'voucher') {
|
||||||
|
$codeSt = $pdo->prepare("SELECT 1 FROM gift_vouchers WHERE idschool = ? AND code = ?");
|
||||||
|
do {
|
||||||
|
$code = 'YB-' . self::randomCode(4) . '-' . self::randomCode(4);
|
||||||
|
$codeSt->execute([$idschool, $code]);
|
||||||
|
} while ($codeSt->fetchColumn());
|
||||||
|
$vExpire = $v['validity_value'] ? self::addPeriod($today, (int) $v['validity_value'], (string) $v['validity_unit'])->format('Y-m-d') : null;
|
||||||
|
$pdo->prepare(
|
||||||
|
"INSERT INTO gift_vouchers (idschool, code, idvariant, buyer_iduser, buyer_name, buyer_email, recipient_name, recipient_email,
|
||||||
|
message, source, amount, expires_at, status)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||||
|
)->execute([
|
||||||
|
$idschool,
|
||||||
|
$code,
|
||||||
|
(int) $v['target_idvariant'],
|
||||||
|
$userId,
|
||||||
|
trim($u['first_name'] . ' ' . $u['last_name']),
|
||||||
|
$u['email'],
|
||||||
|
$sel['recipient']['name'],
|
||||||
|
$sel['recipient']['email'],
|
||||||
|
$sel['recipient']['message'] ?: null,
|
||||||
|
$method,
|
||||||
|
$total,
|
||||||
|
$vExpire,
|
||||||
|
$paid ? 'active' : 'pending',
|
||||||
|
]);
|
||||||
|
// collega il buono all'ordine (per attivarlo alla conferma del pagamento)
|
||||||
|
$pdo->prepare("UPDATE orderbook SET cod = ? WHERE idorderbook = ?")->execute([$code, $idorder]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode === 'membership' && $paid) {
|
||||||
|
$pdo->prepare("INSERT INTO memberships (idschool, iduser, idorderbook, valid_from, valid_to, status) VALUES (?, ?, ?, ?, ?, 'active')")
|
||||||
|
->execute([$idschool, $userId, $idorder, $today, $expire ?? '2099-12-31']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($coupon) {
|
||||||
|
$pdo->prepare("INSERT INTO coupon_redemptions (idcoupon, idschool, iduser, idorderbook, discount_amount) VALUES (?, ?, ?, ?, ?)")
|
||||||
|
->execute([(int) $coupon['idcoupon'], $idschool, $userId, $idorder, $discount]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
return $idorder;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dati del bonifico per un ordine: intestatario, IBAN, banca, causale, scadenza */
|
||||||
|
public static function bankInfo(int $idschool, array $order): array
|
||||||
|
{
|
||||||
|
$tpl = trim((string) SchoolSettings::get('bank_reference', '', $idschool)) ?: 'Ordine {ordine} - {nome}';
|
||||||
|
$iban = strtoupper(preg_replace('/\s+/', '', (string) SchoolSettings::get('bank_iban', '', $idschool)));
|
||||||
|
$days = max(1, (int) SchoolSettings::get('bank_due_days', 5, $idschool));
|
||||||
|
$created = $order['order_date_created'] ?: date('Y-m-d');
|
||||||
|
return [
|
||||||
|
'holder' => (string) SchoolSettings::get('bank_holder', '', $idschool),
|
||||||
|
'iban' => trim(chunk_split($iban, 4, ' ')),
|
||||||
|
'bank' => (string) SchoolSettings::get('bank_name', '', $idschool),
|
||||||
|
'reference' => mb_substr(strtr($tpl, ['{ordine}' => (string) $order['idorderbook'], '{nome}' => trim($order['first_name'] . ' ' . $order['last_name'])]), 0, 140),
|
||||||
|
'due' => date('Y-m-d', strtotime($created . ' +' . $days . ' days')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La scuola conferma il pagamento (bonifico ricevuto) di un ordine in attesa.
|
||||||
|
* - ordine pagato
|
||||||
|
* - lezione singola: la prenotazione passa da 'pending' a 'booked'
|
||||||
|
* - tessera: nasce la riga in memberships
|
||||||
|
* - buono regalo: diventa attivo
|
||||||
|
* Idempotente: false se l'ordine non è (più) in attesa.
|
||||||
|
*/
|
||||||
|
public static function markPaid(int $idschool, int $idorder): bool
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
$st = $pdo->prepare(
|
||||||
|
"SELECT ob.*, p.kind FROM orderbook ob LEFT JOIN products p ON p.idproduct = ob.idproduct
|
||||||
|
WHERE ob.idorderbook = ? AND ob.idschool = ? FOR UPDATE"
|
||||||
|
);
|
||||||
|
$st->execute([$idorder, $idschool]);
|
||||||
|
$o = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$o || $o['payment_status'] !== 'pending') {
|
||||||
|
$pdo->rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classe fissa: 'pending' = da propagare (stesso significato degli ordini storici)
|
||||||
|
$pdo->prepare("UPDATE orderbook SET payment_status = 'paid', status = ? WHERE idorderbook = ? AND idschool = ?")
|
||||||
|
->execute([$o['booking_mode'] === 'fixed' ? 'pending' : 'completed', $idorder, $idschool]);
|
||||||
|
|
||||||
|
if ($o['booking_mode'] === 'single') {
|
||||||
|
$pdo->prepare("UPDATE bookingclass SET status = 'booked' WHERE idorder = ? AND idschool = ? AND status = 'pending'")
|
||||||
|
->execute([$idorder, $idschool]);
|
||||||
|
}
|
||||||
|
if ($o['kind'] === 'membership') {
|
||||||
|
$pdo->prepare("INSERT INTO memberships (idschool, iduser, idorderbook, valid_from, valid_to, status) VALUES (?, ?, ?, CURDATE(), ?, 'active')")
|
||||||
|
->execute([$idschool, (int) $o['iduser'], $idorder, $o['expireon'] ?: '2099-12-31']);
|
||||||
|
}
|
||||||
|
if (!empty($o['cod'])) {
|
||||||
|
$pdo->prepare("UPDATE gift_vouchers SET status = 'active' WHERE idschool = ? AND code = ? AND status = 'pending'")
|
||||||
|
->execute([$idschool, $o['cod']]);
|
||||||
|
}
|
||||||
|
$pdo->commit();
|
||||||
|
return true;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annulla un ordine in attesa di pagamento (dall'allieva o dalla scuola):
|
||||||
|
* libera il posto della lezione singola, annulla il buono e l'uso del coupon.
|
||||||
|
* $userId: se indicato, solo se l'ordine è suo.
|
||||||
|
*/
|
||||||
|
public static function cancelPending(int $idschool, int $idorder, ?int $userId = null): bool
|
||||||
|
{
|
||||||
|
$pdo = self::pdo();
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
$sql = "SELECT * FROM orderbook WHERE idorderbook = ? AND idschool = ?" . ($userId ? " AND iduser = ?" : "") . " FOR UPDATE";
|
||||||
|
$args = $userId ? [$idorder, $idschool, $userId] : [$idorder, $idschool];
|
||||||
|
$st = $pdo->prepare($sql);
|
||||||
|
$st->execute($args);
|
||||||
|
$o = $st->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if (!$o || $o['payment_status'] !== 'pending') {
|
||||||
|
$pdo->rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$pdo->prepare("UPDATE orderbook SET payment_status = 'cancelled', status = 'cancelled' WHERE idorderbook = ? AND idschool = ?")
|
||||||
|
->execute([$idorder, $idschool]);
|
||||||
|
$pdo->prepare("UPDATE bookingclass SET status = 'cancelled' WHERE idorder = ? AND idschool = ? AND status <> 'cancelled'")
|
||||||
|
->execute([$idorder, $idschool]);
|
||||||
|
$pdo->prepare("DELETE FROM coupon_redemptions WHERE idorderbook = ? AND idschool = ?")->execute([$idorder, $idschool]);
|
||||||
|
if (!empty($o['cod'])) {
|
||||||
|
$pdo->prepare("UPDATE gift_vouchers SET status = 'cancelled' WHERE idschool = ? AND code = ? AND status = 'pending'")
|
||||||
|
->execute([$idschool, $o['cod']]);
|
||||||
|
}
|
||||||
|
$pdo->commit();
|
||||||
|
return true;
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
if ($pdo->inTransaction()) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ordini su cui la scuola deve agire: da pagare + da propagare (contatore in sidebar) */
|
||||||
|
public static function pendingCount(int $idschool): int
|
||||||
|
{
|
||||||
|
$st = self::pdo()->prepare(
|
||||||
|
"SELECT COUNT(*) FROM orderbook
|
||||||
|
WHERE idschool = ?
|
||||||
|
AND (payment_status = 'pending'
|
||||||
|
OR (status = 'pending' AND (payment_status IS NULL OR payment_status = 'paid')))"
|
||||||
|
);
|
||||||
|
$st->execute([$idschool]);
|
||||||
|
return (int) $st->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function randomCode(int $len): string
|
||||||
|
{
|
||||||
|
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||||||
|
$out = '';
|
||||||
|
for ($i = 0; $i < $len; $i++) {
|
||||||
|
$out .= $chars[random_int(0, strlen($chars) - 1)];
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function pdo(): PDO
|
||||||
|
{
|
||||||
|
return DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,34 +5,42 @@ require_once('include/headscript.php');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Conferma una prenotazione in attesa: pending -> booked.
|
* Conferma una prenotazione in attesa: pending -> booked.
|
||||||
|
* POST: idbookingclass. Risposta JSON. Solo staff, solo scuola corrente.
|
||||||
*/
|
*/
|
||||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||||
|
|
||||||
function jsonOut(array $payload): void
|
function jsonOut(array $payload, int $code = 200): void
|
||||||
{
|
{
|
||||||
if (ob_get_length() !== false) {
|
if (ob_get_length() !== false) {
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
}
|
}
|
||||||
|
http_response_code($code);
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SchoolContext::isStaff()) {
|
||||||
|
jsonOut(['success' => false, 'error' => 'Accesso non autorizzato.'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
$idbookingclass = isset($_POST['idbookingclass']) ? (int) $_POST['idbookingclass'] : 0;
|
$idbookingclass = isset($_POST['idbookingclass']) ? (int) $_POST['idbookingclass'] : 0;
|
||||||
|
|
||||||
if ($idbookingclass <= 0) {
|
if ($idbookingclass <= 0) {
|
||||||
jsonOut(['success' => false, 'error' => 'ID prenotazione non valido.']);
|
jsonOut(['success' => false, 'error' => 'ID prenotazione non valido.'], 400);
|
||||||
|
}
|
||||||
|
if (!SchoolScope::belongs('bookingclass', $idbookingclass)) {
|
||||||
|
jsonOut(['success' => false, 'error' => 'Prenotazione non trovata in questa scuola.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Conferma solo se effettivamente in pending (evita conferme accidentali)
|
$stmt = $pdo->prepare("UPDATE bookingclass SET status = 'booked' WHERE idbookingclass = :id AND idschool = :idschool AND status = 'pending'");
|
||||||
$stmt = $pdo->prepare(
|
$stmt->execute([':id' => $idbookingclass, ':idschool' => $idschool]);
|
||||||
"UPDATE bookingclass SET status = 'booked'
|
if ($stmt->rowCount() === 0) {
|
||||||
WHERE idbookingclass = :id AND status = 'pending'"
|
jsonOut(['success' => false, 'error' => 'La prenotazione non è più in attesa.'], 409);
|
||||||
);
|
}
|
||||||
$stmt->execute([':id' => $idbookingclass]);
|
|
||||||
jsonOut(['success' => true]);
|
jsonOut(['success' => true]);
|
||||||
} catch (Throwable $ex) {
|
} catch (Throwable $ex) {
|
||||||
error_log('conferma_pending error: ' . $ex->getMessage());
|
error_log('conferma_pending error: ' . $ex->getMessage());
|
||||||
jsonOut(['success' => false, 'error' => 'Errore durante la conferma.']);
|
jsonOut(['success' => false, 'error' => 'Errore durante la conferma.'], 500);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,866 +0,0 @@
|
|||||||
/*
|
|
||||||
Author: Themesdesign
|
|
||||||
Website: https://themesdesign.in/
|
|
||||||
Contact: support@Themesdesign.com
|
|
||||||
*/
|
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap");
|
|
||||||
.right-side-nav {
|
|
||||||
padding: 24px;
|
|
||||||
border-left: 1px solid #eff2f7;
|
|
||||||
background-color: #fff;
|
|
||||||
position: sticky;
|
|
||||||
top: 94px;
|
|
||||||
height: calc(100vh - 180px);
|
|
||||||
margin-left: 24px; }
|
|
||||||
@media (min-width: 1200px) {
|
|
||||||
.right-side-nav {
|
|
||||||
min-width: 270px; } }
|
|
||||||
.right-side-nav .nav-item .nav-link.active {
|
|
||||||
background-color: #eff2f7;
|
|
||||||
color: #495057; }
|
|
||||||
|
|
||||||
#page-topbar {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1002;
|
|
||||||
background-color: #ffffff;
|
|
||||||
-webkit-box-shadow: 0 0.75rem 1.5rem rgba(18, 38, 63, 0.03);
|
|
||||||
box-shadow: 0 0.75rem 1.5rem rgba(18, 38, 63, 0.03); }
|
|
||||||
|
|
||||||
.navbar-header {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-ms-flex-pack: justify;
|
|
||||||
-webkit-box-pack: justify;
|
|
||||||
justify-content: space-between;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0 auto;
|
|
||||||
height: 70px;
|
|
||||||
padding: 0 calc(24px / 2) 0 0; }
|
|
||||||
.navbar-header .dropdown.show .header-item {
|
|
||||||
background-color: #f8f9fa; }
|
|
||||||
|
|
||||||
.navbar-brand-box {
|
|
||||||
padding: 0 1.5rem;
|
|
||||||
width: 250px; }
|
|
||||||
.navbar-brand-box .logo-txt {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 18px;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 5px; }
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
line-height: 70px; }
|
|
||||||
.logo .logo-sm {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
.logo-light {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
/* Search */
|
|
||||||
.app-search {
|
|
||||||
padding: calc(32px / 2) 0; }
|
|
||||||
.app-search .form-control {
|
|
||||||
border: none;
|
|
||||||
height: 38px;
|
|
||||||
padding-left: 40px;
|
|
||||||
padding-right: 20px;
|
|
||||||
background-color: #f3f3f9;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
box-shadow: none;
|
|
||||||
border-radius: 30px; }
|
|
||||||
.app-search span {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 38px;
|
|
||||||
left: 13px;
|
|
||||||
top: 0;
|
|
||||||
color: #74788d; }
|
|
||||||
|
|
||||||
.megamenu-list li {
|
|
||||||
position: relative;
|
|
||||||
padding: 5px 0px; }
|
|
||||||
.megamenu-list li a {
|
|
||||||
color: #495057; }
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
.navbar-brand-box {
|
|
||||||
width: auto; }
|
|
||||||
.logo span.logo-lg {
|
|
||||||
display: none; }
|
|
||||||
.logo span.logo-sm {
|
|
||||||
display: inline-block; } }
|
|
||||||
|
|
||||||
.page-content {
|
|
||||||
padding: calc(70px + 24px) calc(24px / 2) 60px calc(24px / 2); }
|
|
||||||
|
|
||||||
.header-item {
|
|
||||||
height: 70px;
|
|
||||||
-webkit-box-shadow: none !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
color: #555b6d;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0px;
|
|
||||||
line-height: 70px;
|
|
||||||
padding: 0px 12px; }
|
|
||||||
.header-item:hover {
|
|
||||||
color: #555b6d; }
|
|
||||||
|
|
||||||
.header-profile-user {
|
|
||||||
height: 36px;
|
|
||||||
width: 36px;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
padding: 3px; }
|
|
||||||
|
|
||||||
.noti-icon i {
|
|
||||||
font-size: 22px;
|
|
||||||
color: #555b6d; }
|
|
||||||
|
|
||||||
.noti-icon .badge {
|
|
||||||
position: absolute;
|
|
||||||
top: 12px; }
|
|
||||||
|
|
||||||
.notification-item .media {
|
|
||||||
padding: 0.75rem 1rem; }
|
|
||||||
.notification-item .media:hover {
|
|
||||||
background-color: #f6f6f6; }
|
|
||||||
|
|
||||||
.dropdown-icon-item {
|
|
||||||
display: block;
|
|
||||||
border-radius: 3px;
|
|
||||||
line-height: 34px;
|
|
||||||
text-align: center;
|
|
||||||
padding: 15px 0 9px;
|
|
||||||
display: block;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
color: #74788d; }
|
|
||||||
.dropdown-icon-item img {
|
|
||||||
height: 24px; }
|
|
||||||
.dropdown-icon-item span {
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap; }
|
|
||||||
.dropdown-icon-item:hover {
|
|
||||||
border-color: #eff2f7; }
|
|
||||||
|
|
||||||
.fullscreen-enable [data-toggle="fullscreen"] .bx-fullscreen::before {
|
|
||||||
content: "\ea3f"; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] #page-topbar {
|
|
||||||
background-color: #2a3042; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .navbar-header .dropdown.show .header-item {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05); }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .navbar-header .waves-effect .waves-ripple {
|
|
||||||
background: rgba(255, 255, 255, 0.4); }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .header-item {
|
|
||||||
color: #e9ecef; }
|
|
||||||
body[data-topbar="dark"] .header-item:hover {
|
|
||||||
color: #e9ecef; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .header-profile-user {
|
|
||||||
background-color: rgba(255, 255, 255, 0.25); }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .noti-icon i {
|
|
||||||
color: #e9ecef; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .logo-dark {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .logo-light {
|
|
||||||
display: block; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .app-search .form-control {
|
|
||||||
background-color: rgba(243, 243, 249, 0.07);
|
|
||||||
color: #fff; }
|
|
||||||
|
|
||||||
body[data-topbar="dark"] .app-search span,
|
|
||||||
body[data-topbar="dark"] .app-search input.form-control::-webkit-input-placeholder {
|
|
||||||
color: rgba(255, 255, 255, 0.5); }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] .navbar-brand-box {
|
|
||||||
background: #2a3042; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] .logo-dark {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] .logo-light {
|
|
||||||
display: block; }
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.navbar-header .dropdown {
|
|
||||||
position: static; }
|
|
||||||
.navbar-header .dropdown .dropdown-menu {
|
|
||||||
left: 10px !important;
|
|
||||||
right: 10px !important; } }
|
|
||||||
|
|
||||||
@media (max-width: 380px) {
|
|
||||||
.navbar-brand-box {
|
|
||||||
display: none; } }
|
|
||||||
|
|
||||||
body[data-layout="horizontal"] .navbar-brand-box {
|
|
||||||
width: auto; }
|
|
||||||
|
|
||||||
body[data-layout="horizontal"] .page-content {
|
|
||||||
margin-top: 70px;
|
|
||||||
padding: calc(55px + 24px) calc(24px / 2) 60px calc(24px / 2); }
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
body[data-layout="horizontal"] .page-content {
|
|
||||||
margin-top: 15px; } }
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
bottom: 0;
|
|
||||||
padding: 20px calc(24px / 2);
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
color: #74788d;
|
|
||||||
left: 250px;
|
|
||||||
height: 60px;
|
|
||||||
background-color: #eff2f7; }
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
.footer {
|
|
||||||
left: 0; } }
|
|
||||||
|
|
||||||
.vertical-collpsed .footer {
|
|
||||||
left: 70px; }
|
|
||||||
|
|
||||||
body[data-layout="horizontal"] .footer {
|
|
||||||
left: 0 !important; }
|
|
||||||
|
|
||||||
.metismenu {
|
|
||||||
margin: 0; }
|
|
||||||
.metismenu li {
|
|
||||||
display: block;
|
|
||||||
width: 100%; }
|
|
||||||
.metismenu .mm-collapse {
|
|
||||||
display: none; }
|
|
||||||
.metismenu .mm-collapse:not(.mm-show) {
|
|
||||||
display: none; }
|
|
||||||
.metismenu .mm-collapse.mm-show {
|
|
||||||
display: block; }
|
|
||||||
.metismenu .mm-collapsing {
|
|
||||||
position: relative;
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
-webkit-transition-timing-function: ease;
|
|
||||||
transition-timing-function: ease;
|
|
||||||
-webkit-transition-duration: .35s;
|
|
||||||
transition-duration: .35s;
|
|
||||||
-webkit-transition-property: height, visibility;
|
|
||||||
transition-property: height, visibility; }
|
|
||||||
|
|
||||||
.vertical-menu {
|
|
||||||
width: 250px;
|
|
||||||
z-index: 1001;
|
|
||||||
background: #f3f6fb;
|
|
||||||
bottom: 0;
|
|
||||||
margin-top: 0;
|
|
||||||
position: fixed;
|
|
||||||
top: 70px;
|
|
||||||
-webkit-box-shadow: 0 0.75rem 1.5rem rgba(18, 38, 63, 0.03);
|
|
||||||
box-shadow: 0 0.75rem 1.5rem rgba(18, 38, 63, 0.03); }
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
margin-left: 250px; }
|
|
||||||
.main-content .content {
|
|
||||||
padding: 0 15px 10px 15px;
|
|
||||||
margin-top: 70px; }
|
|
||||||
|
|
||||||
#sidebar-menu {
|
|
||||||
padding: 10px 0 30px 0; }
|
|
||||||
#sidebar-menu .mm-active > .has-arrow:after {
|
|
||||||
-webkit-transform: rotate(-180deg);
|
|
||||||
transform: rotate(-180deg); }
|
|
||||||
#sidebar-menu .has-arrow:after {
|
|
||||||
content: "\F0140";
|
|
||||||
font-family: 'Material Design Icons';
|
|
||||||
display: block;
|
|
||||||
float: right;
|
|
||||||
-webkit-transition: -webkit-transform .2s;
|
|
||||||
transition: -webkit-transform .2s;
|
|
||||||
transition: transform .2s;
|
|
||||||
transition: transform .2s, -webkit-transform .2s;
|
|
||||||
font-size: 1rem; }
|
|
||||||
#sidebar-menu ul li a {
|
|
||||||
display: block;
|
|
||||||
padding: .625rem 1.5rem;
|
|
||||||
color: #545a6d;
|
|
||||||
position: relative;
|
|
||||||
font-weight: 600;
|
|
||||||
-webkit-transition: all .4s;
|
|
||||||
transition: all .4s; }
|
|
||||||
#sidebar-menu ul li a i {
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 1.75rem;
|
|
||||||
padding-bottom: .125em;
|
|
||||||
font-size: 1.07rem;
|
|
||||||
line-height: 1.40625rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
-webkit-transition: all .4s;
|
|
||||||
transition: all .4s; }
|
|
||||||
#sidebar-menu ul li a:hover {
|
|
||||||
color: #383c40; }
|
|
||||||
#sidebar-menu ul li a:hover i {
|
|
||||||
color: #383c40; }
|
|
||||||
#sidebar-menu ul li .badge {
|
|
||||||
margin-top: 4px; }
|
|
||||||
#sidebar-menu ul li ul.sub-menu {
|
|
||||||
padding: 0; }
|
|
||||||
#sidebar-menu ul li ul.sub-menu li a {
|
|
||||||
padding: .4rem 1.5rem .4rem 3.5rem;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #545a6d; }
|
|
||||||
#sidebar-menu ul li ul.sub-menu li ul.sub-menu {
|
|
||||||
padding: 0; }
|
|
||||||
#sidebar-menu ul li ul.sub-menu li ul.sub-menu li a {
|
|
||||||
padding: .4rem 1.5rem .4rem 4.5rem;
|
|
||||||
font-size: 13.5px; }
|
|
||||||
|
|
||||||
.menu-title {
|
|
||||||
padding: 12px 20px !important;
|
|
||||||
letter-spacing: .05em;
|
|
||||||
pointer-events: none;
|
|
||||||
cursor: default;
|
|
||||||
font-size: 11px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: #7f8387;
|
|
||||||
font-weight: 600; }
|
|
||||||
|
|
||||||
.mm-active {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
.mm-active .active {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
.mm-active .active i {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
.mm-active > i {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
.vertical-menu {
|
|
||||||
display: none; }
|
|
||||||
.main-content {
|
|
||||||
margin-left: 0 !important; }
|
|
||||||
body.sidebar-enable .vertical-menu {
|
|
||||||
display: block; } }
|
|
||||||
|
|
||||||
.vertical-collpsed .main-content {
|
|
||||||
margin-left: 70px; }
|
|
||||||
|
|
||||||
.vertical-collpsed .navbar-brand-box {
|
|
||||||
width: 70px !important; }
|
|
||||||
|
|
||||||
.vertical-collpsed .logo span.logo-lg {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
.vertical-collpsed .logo span.logo-sm {
|
|
||||||
display: block; }
|
|
||||||
|
|
||||||
.vertical-collpsed .vertical-menu {
|
|
||||||
position: absolute;
|
|
||||||
width: 70px !important;
|
|
||||||
z-index: 5; }
|
|
||||||
.vertical-collpsed .vertical-menu .simplebar-mask,
|
|
||||||
.vertical-collpsed .vertical-menu .simplebar-content-wrapper {
|
|
||||||
overflow: visible !important; }
|
|
||||||
.vertical-collpsed .vertical-menu .simplebar-scrollbar {
|
|
||||||
display: none !important; }
|
|
||||||
.vertical-collpsed .vertical-menu .simplebar-offset {
|
|
||||||
bottom: 0 !important; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu .menu-title,
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu .badge,
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu .collapse.in {
|
|
||||||
display: none !important; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu .nav.collapse {
|
|
||||||
height: inherit !important; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu .has-arrow:after {
|
|
||||||
display: none; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li {
|
|
||||||
position: relative;
|
|
||||||
white-space: nowrap; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a {
|
|
||||||
padding: 15px 20px;
|
|
||||||
min-height: 55px;
|
|
||||||
-webkit-transition: none;
|
|
||||||
transition: none; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a:hover, .vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a:active, .vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a:focus {
|
|
||||||
color: #383c40; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a i {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
margin-left: 4px; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a span {
|
|
||||||
display: none;
|
|
||||||
padding-left: 25px; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a {
|
|
||||||
position: relative;
|
|
||||||
width: calc(190px + 70px);
|
|
||||||
color: #556ee6;
|
|
||||||
background-color: #e4ebf6;
|
|
||||||
-webkit-transition: none;
|
|
||||||
transition: none; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a i {
|
|
||||||
color: #556ee6; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a span {
|
|
||||||
display: inline; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > ul {
|
|
||||||
display: block;
|
|
||||||
left: 70px;
|
|
||||||
position: absolute;
|
|
||||||
width: 190px;
|
|
||||||
height: auto !important;
|
|
||||||
-webkit-box-shadow: 3px 5px 10px 0 rgba(54, 61, 71, 0.1);
|
|
||||||
box-shadow: 3px 5px 10px 0 rgba(54, 61, 71, 0.1); }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > ul ul {
|
|
||||||
-webkit-box-shadow: 3px 5px 10px 0 rgba(54, 61, 71, 0.1);
|
|
||||||
box-shadow: 3px 5px 10px 0 rgba(54, 61, 71, 0.1); }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > ul a {
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
box-shadow: none;
|
|
||||||
padding: 8px 20px;
|
|
||||||
position: relative;
|
|
||||||
width: 190px;
|
|
||||||
z-index: 6;
|
|
||||||
color: #545a6d; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > ul a:hover {
|
|
||||||
color: #383c40; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul ul {
|
|
||||||
padding: 5px 0;
|
|
||||||
z-index: 9999;
|
|
||||||
display: none;
|
|
||||||
background-color: #f3f6fb; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul ul li:hover > ul {
|
|
||||||
display: block;
|
|
||||||
left: 190px;
|
|
||||||
height: auto !important;
|
|
||||||
margin-top: -36px;
|
|
||||||
position: absolute;
|
|
||||||
width: 190px; }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul ul li > a span.pull-right {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
top: 12px;
|
|
||||||
-webkit-transform: rotate(270deg);
|
|
||||||
transform: rotate(270deg); }
|
|
||||||
.vertical-collpsed .vertical-menu #sidebar-menu > ul ul li.active a {
|
|
||||||
color: #f8f9fa; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] .vertical-menu {
|
|
||||||
background: #2a3042; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] #sidebar-menu ul li a {
|
|
||||||
color: #858ea8; }
|
|
||||||
body[data-sidebar="dark"] #sidebar-menu ul li a i {
|
|
||||||
color: #6a7187; }
|
|
||||||
body[data-sidebar="dark"] #sidebar-menu ul li a:hover {
|
|
||||||
color: #ffffff; }
|
|
||||||
body[data-sidebar="dark"] #sidebar-menu ul li a:hover i {
|
|
||||||
color: #ffffff; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu li a {
|
|
||||||
color: #79829c; }
|
|
||||||
body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu li a:hover {
|
|
||||||
color: #ffffff; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed {
|
|
||||||
min-height: 1300px; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a {
|
|
||||||
background: #2e3548;
|
|
||||||
color: #ffffff; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a i {
|
|
||||||
color: #ffffff; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > ul a {
|
|
||||||
color: #79829c; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > ul a:hover {
|
|
||||||
color: #ffffff; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul ul {
|
|
||||||
background-color: #2a3042; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu ul li.mm-active .active {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu ul li.mm-active .active i {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] .mm-active {
|
|
||||||
color: #ffffff !important; }
|
|
||||||
body[data-sidebar="dark"] .mm-active > i {
|
|
||||||
color: #ffffff !important; }
|
|
||||||
body[data-sidebar="dark"] .mm-active .active {
|
|
||||||
color: #ffffff !important; }
|
|
||||||
body[data-sidebar="dark"] .mm-active .active i {
|
|
||||||
color: #ffffff !important; }
|
|
||||||
|
|
||||||
body[data-sidebar="dark"] .menu-title {
|
|
||||||
color: #6a7187; }
|
|
||||||
|
|
||||||
body[data-layout="horizontal"] .main-content {
|
|
||||||
margin-left: 0 !important; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] .navbar-brand-box {
|
|
||||||
width: 160px; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] .vertical-menu {
|
|
||||||
width: 160px;
|
|
||||||
text-align: center; }
|
|
||||||
body[data-sidebar-size="small"] .vertical-menu .has-arrow:after,
|
|
||||||
body[data-sidebar-size="small"] .vertical-menu .badge {
|
|
||||||
display: none !important; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] .main-content {
|
|
||||||
margin-left: 160px; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] .footer {
|
|
||||||
left: 160px; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] #sidebar-menu ul li.menu-title {
|
|
||||||
background-color: #2e3548; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] #sidebar-menu ul li a i {
|
|
||||||
display: block; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"] #sidebar-menu ul li ul.sub-menu li a {
|
|
||||||
padding-left: 1.5rem; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"].vertical-collpsed .main-content {
|
|
||||||
margin-left: 70px; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"].vertical-collpsed .vertical-menu #sidebar-menu {
|
|
||||||
text-align: left; }
|
|
||||||
body[data-sidebar-size="small"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li > a i {
|
|
||||||
display: inline-block; }
|
|
||||||
|
|
||||||
body[data-sidebar-size="small"].vertical-collpsed .footer {
|
|
||||||
left: 70px; }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"] .vertical-menu {
|
|
||||||
background-color: #556ee6; }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"] .navbar-brand-box {
|
|
||||||
background-color: #556ee6; }
|
|
||||||
body[data-sidebar="colored"] .navbar-brand-box .logo-dark {
|
|
||||||
display: none; }
|
|
||||||
body[data-sidebar="colored"] .navbar-brand-box .logo-light {
|
|
||||||
display: block; }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"] .mm-active {
|
|
||||||
color: #fff !important; }
|
|
||||||
body[data-sidebar="colored"] .mm-active > i, body[data-sidebar="colored"] .mm-active .active {
|
|
||||||
color: #fff !important; }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"] #sidebar-menu ul li.menu-title {
|
|
||||||
color: rgba(255, 255, 255, 0.6); }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"] #sidebar-menu ul li a {
|
|
||||||
color: rgba(255, 255, 255, 0.6); }
|
|
||||||
body[data-sidebar="colored"] #sidebar-menu ul li a i {
|
|
||||||
color: rgba(255, 255, 255, 0.6); }
|
|
||||||
body[data-sidebar="colored"] #sidebar-menu ul li a.waves-effect .waves-ripple {
|
|
||||||
background: rgba(255, 255, 255, 0.1); }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"] #sidebar-menu ul li ul.sub-menu li a {
|
|
||||||
color: rgba(255, 255, 255, 0.5); }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a {
|
|
||||||
background-color: #5e76e7;
|
|
||||||
color: #fff; }
|
|
||||||
body[data-sidebar="colored"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a i {
|
|
||||||
color: #fff; }
|
|
||||||
|
|
||||||
body[data-sidebar="colored"].vertical-collpsed .vertical-menu #sidebar-menu ul li.mm-active .active {
|
|
||||||
color: #556ee6 !important; }
|
|
||||||
|
|
||||||
.font-size-10 {
|
|
||||||
font-size: 10px !important; }
|
|
||||||
|
|
||||||
.font-size-11 {
|
|
||||||
font-size: 11px !important; }
|
|
||||||
|
|
||||||
.font-size-12 {
|
|
||||||
font-size: 12px !important; }
|
|
||||||
|
|
||||||
.font-size-13 {
|
|
||||||
font-size: 13px !important; }
|
|
||||||
|
|
||||||
.font-size-14 {
|
|
||||||
font-size: 14px !important; }
|
|
||||||
|
|
||||||
.font-size-15 {
|
|
||||||
font-size: 15px !important; }
|
|
||||||
|
|
||||||
.font-size-16 {
|
|
||||||
font-size: 16px !important; }
|
|
||||||
|
|
||||||
.font-size-17 {
|
|
||||||
font-size: 17px !important; }
|
|
||||||
|
|
||||||
.font-size-18 {
|
|
||||||
font-size: 18px !important; }
|
|
||||||
|
|
||||||
.font-size-20 {
|
|
||||||
font-size: 20px !important; }
|
|
||||||
|
|
||||||
.font-size-22 {
|
|
||||||
font-size: 22px !important; }
|
|
||||||
|
|
||||||
.font-size-24 {
|
|
||||||
font-size: 24px !important; }
|
|
||||||
|
|
||||||
.font-weight-medium {
|
|
||||||
font-weight: 600; }
|
|
||||||
|
|
||||||
.font-weight-semibold {
|
|
||||||
font-weight: 600; }
|
|
||||||
|
|
||||||
.social-list-item {
|
|
||||||
height: 2rem;
|
|
||||||
width: 2rem;
|
|
||||||
line-height: calc(2rem - 2px);
|
|
||||||
display: block;
|
|
||||||
border: 1px solid #adb5bd;
|
|
||||||
border-radius: 50%;
|
|
||||||
color: #adb5bd;
|
|
||||||
text-align: center;
|
|
||||||
-webkit-transition: all 0.4s;
|
|
||||||
transition: all 0.4s; }
|
|
||||||
.social-list-item:hover {
|
|
||||||
color: #74788d;
|
|
||||||
background-color: #eff2f7; }
|
|
||||||
|
|
||||||
.w-xs {
|
|
||||||
min-width: 80px; }
|
|
||||||
|
|
||||||
.w-sm {
|
|
||||||
min-width: 95px; }
|
|
||||||
|
|
||||||
.w-md {
|
|
||||||
min-width: 110px; }
|
|
||||||
|
|
||||||
.w-lg {
|
|
||||||
min-width: 140px; }
|
|
||||||
|
|
||||||
.w-xl {
|
|
||||||
min-width: 160px; }
|
|
||||||
|
|
||||||
[data-simplebar] {
|
|
||||||
position: relative;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-box-direction: normal;
|
|
||||||
-ms-flex-direction: column;
|
|
||||||
flex-direction: column;
|
|
||||||
-ms-flex-wrap: wrap;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
-webkit-box-pack: start;
|
|
||||||
-ms-flex-pack: start;
|
|
||||||
justify-content: flex-start;
|
|
||||||
-ms-flex-line-pack: start;
|
|
||||||
align-content: flex-start;
|
|
||||||
-webkit-box-align: start;
|
|
||||||
-ms-flex-align: start;
|
|
||||||
align-items: flex-start; }
|
|
||||||
|
|
||||||
.simplebar-wrapper {
|
|
||||||
overflow: hidden;
|
|
||||||
width: inherit;
|
|
||||||
height: inherit;
|
|
||||||
max-width: inherit;
|
|
||||||
max-height: inherit; }
|
|
||||||
|
|
||||||
.simplebar-mask {
|
|
||||||
direction: inherit;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
width: auto !important;
|
|
||||||
height: auto !important;
|
|
||||||
z-index: 0; }
|
|
||||||
|
|
||||||
.simplebar-offset {
|
|
||||||
direction: inherit !important;
|
|
||||||
-webkit-box-sizing: inherit !important;
|
|
||||||
box-sizing: inherit !important;
|
|
||||||
resize: none !important;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0 !important;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0 !important;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
-webkit-overflow-scrolling: touch; }
|
|
||||||
|
|
||||||
.simplebar-content-wrapper {
|
|
||||||
direction: inherit;
|
|
||||||
-webkit-box-sizing: border-box !important;
|
|
||||||
box-sizing: border-box !important;
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
height: 100%;
|
|
||||||
/* Required for horizontal native scrollbar to not appear if parent is taller than natural height */
|
|
||||||
width: auto;
|
|
||||||
visibility: visible;
|
|
||||||
overflow: auto;
|
|
||||||
/* Scroll on this element otherwise element can't have a padding applied properly */
|
|
||||||
max-width: 100%;
|
|
||||||
/* Not required for horizontal scroll to trigger */
|
|
||||||
max-height: 100%;
|
|
||||||
/* Needed for vertical scroll to trigger */
|
|
||||||
scrollbar-width: none;
|
|
||||||
padding: 0px !important; }
|
|
||||||
|
|
||||||
.simplebar-content-wrapper::-webkit-scrollbar,
|
|
||||||
.simplebar-hide-scrollbar::-webkit-scrollbar {
|
|
||||||
display: none; }
|
|
||||||
|
|
||||||
.simplebar-content:before,
|
|
||||||
.simplebar-content:after {
|
|
||||||
content: ' ';
|
|
||||||
display: table; }
|
|
||||||
|
|
||||||
.simplebar-placeholder {
|
|
||||||
max-height: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
width: 100%;
|
|
||||||
pointer-events: none; }
|
|
||||||
|
|
||||||
.simplebar-height-auto-observer-wrapper {
|
|
||||||
-webkit-box-sizing: inherit !important;
|
|
||||||
box-sizing: inherit !important;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1px;
|
|
||||||
position: relative;
|
|
||||||
float: left;
|
|
||||||
max-height: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: -1;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
-webkit-box-flex: inherit;
|
|
||||||
-ms-flex-positive: inherit;
|
|
||||||
flex-grow: inherit;
|
|
||||||
-ms-flex-negative: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
-ms-flex-preferred-size: 0;
|
|
||||||
flex-basis: 0; }
|
|
||||||
|
|
||||||
.simplebar-height-auto-observer {
|
|
||||||
-webkit-box-sizing: inherit;
|
|
||||||
box-sizing: inherit;
|
|
||||||
display: block;
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 1000%;
|
|
||||||
width: 1000%;
|
|
||||||
min-height: 1px;
|
|
||||||
min-width: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: -1; }
|
|
||||||
|
|
||||||
.simplebar-track {
|
|
||||||
z-index: 1;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
overflow: hidden; }
|
|
||||||
|
|
||||||
[data-simplebar].simplebar-dragging .simplebar-content {
|
|
||||||
pointer-events: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none; }
|
|
||||||
|
|
||||||
[data-simplebar].simplebar-dragging .simplebar-track {
|
|
||||||
pointer-events: all; }
|
|
||||||
|
|
||||||
.simplebar-scrollbar {
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
width: 7px;
|
|
||||||
min-height: 10px; }
|
|
||||||
|
|
||||||
.simplebar-scrollbar:before {
|
|
||||||
position: absolute;
|
|
||||||
content: '';
|
|
||||||
background: #a2adb7;
|
|
||||||
border-radius: 7px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
opacity: 0;
|
|
||||||
-webkit-transition: opacity 0.2s linear;
|
|
||||||
transition: opacity 0.2s linear; }
|
|
||||||
|
|
||||||
.simplebar-scrollbar.simplebar-visible:before {
|
|
||||||
/* When hovered, remove all transitions from drag handle */
|
|
||||||
opacity: 0.5;
|
|
||||||
-webkit-transition: opacity 0s linear;
|
|
||||||
transition: opacity 0s linear; }
|
|
||||||
|
|
||||||
.simplebar-track.simplebar-vertical {
|
|
||||||
top: 0;
|
|
||||||
width: 11px; }
|
|
||||||
|
|
||||||
.simplebar-track.simplebar-vertical .simplebar-scrollbar:before {
|
|
||||||
top: 2px;
|
|
||||||
bottom: 2px; }
|
|
||||||
|
|
||||||
.simplebar-track.simplebar-horizontal {
|
|
||||||
left: 0;
|
|
||||||
height: 11px; }
|
|
||||||
|
|
||||||
.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before {
|
|
||||||
height: 100%;
|
|
||||||
left: 2px;
|
|
||||||
right: 2px; }
|
|
||||||
|
|
||||||
.simplebar-track.simplebar-horizontal .simplebar-scrollbar {
|
|
||||||
right: auto;
|
|
||||||
left: 0;
|
|
||||||
top: 2px;
|
|
||||||
height: 7px;
|
|
||||||
min-height: 0;
|
|
||||||
min-width: 10px;
|
|
||||||
width: auto; }
|
|
||||||
|
|
||||||
/* Rtl support */
|
|
||||||
[data-simplebar-direction='rtl'] .simplebar-track.simplebar-vertical {
|
|
||||||
right: auto;
|
|
||||||
left: 0; }
|
|
||||||
|
|
||||||
.hs-dummy-scrollbar-size {
|
|
||||||
direction: rtl;
|
|
||||||
position: fixed;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
height: 500px;
|
|
||||||
width: 500px;
|
|
||||||
overflow-y: hidden;
|
|
||||||
overflow-x: scroll; }
|
|
||||||
|
|
||||||
.simplebar-hide-scrollbar {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
overflow-y: scroll;
|
|
||||||
scrollbar-width: none; }
|
|
||||||
|
|
||||||
.custom-scroll {
|
|
||||||
height: 100%; }
|
|
||||||
|
Before Width: | Height: | Size: 727 KiB |
@@ -1,210 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<metadata>Generated by Fontastic.me</metadata>
|
|
||||||
<defs>
|
|
||||||
<font id="dripicons-v2" horiz-adv-x="512">
|
|
||||||
<font-face font-family="dripicons-v2" units-per-em="512" ascent="480" descent="-32"/>
|
|
||||||
<missing-glyph horiz-adv-x="512" />
|
|
||||||
|
|
||||||
<glyph glyph-name="alarm" unicode="a" d="M459 344c6 5 30 28 31 62 0 25-11 47-35 67 0 0 0 1 0 1-28 21-53 22-68 20-27-5-46-25-54-35-24 9-50 14-77 14-27 0-53-5-77-13-8 10-26 30-53 35-16 3-40 1-68-20 0 0-1-1-1-1-24-21-35-43-35-68 1-34 25-57 31-62-13-29-21-61-21-96 0-56 21-108 56-147-1-1-1-1-1-1l-32-49c-7-10-4-24 6-30 4-3 8-4 12-4 7 0 14 3 18 10l29 43c38-29 85-46 136-46 51 0 99 17 136 47l30-44c4-7 11-10 18-10 5 0 9 1 12 4 10 6 13 20 7 30l-33 49c0 0-1 1-1 1 34 40 54 91 54 147 1 35-7 67-20 96z m-64 106c9 2 20-2 31-11 13-11 19-22 19-32 0-10-5-19-10-24-17 22-38 41-61 56 6 5 13 10 21 11z m-328-43c0 10 6 21 19 32 11 9 22 13 31 11 8-1 15-6 21-11-23-15-44-34-61-56-4 6-10 14-10 24z m189-339c-99 0-179 81-179 180 0 99 80 181 179 181 99 0 179-81 179-180 0-99-80-181-179-181z m81 131c9-9 9-23 0-31-5-5-10-7-16-7-5 0-11 2-15 7l-66 65c-3 4-6 10-6 15l0 120c0 13 10 23 22 23 12 0 22-10 22-23l0-110z"/>
|
|
||||||
<glyph glyph-name="align-center" unicode="b" d="M456 412l-400 0c-13 0-23 10-23 22 0 12 10 22 23 22l400 0c13 0 23-10 23-22 0-12-10-22-23-22z m-63-97c0 12-10 22-22 22l-230 0c-12 0-22-10-22-22 0-12 10-22 22-22l230 0c12 0 22 10 22 22z m34-119c0 13-10 23-22 23l-298 0c-12 0-22-10-22-23 0-12 10-22 22-22l298 0c12 0 22 10 22 22z m41-118c0 12-10 22-22 22l-380 0c-12 0-22-10-22-22 0-12 10-22 22-22l379 0c13 0 23 10 23 22z"/>
|
|
||||||
<glyph glyph-name="align-justify" unicode="c" d="M456 412l-400 0c-13 0-23 10-23 22 0 12 10 22 23 22l400 0c13 0 23-10 23-22 0-12-10-22-23-22z m23-97c0 12-10 22-23 22l-400 0c-13 0-23-10-23-22 0-12 10-22 23-22l400 0c13 0 23 10 23 22z m0-119c0 13-10 23-23 23l-400 0c-13 0-23-10-23-23 0-12 10-22 23-22l400 0c13 0 23 10 23 22z m-201-118c0 12-10 22-22 22l-199 0c-12 0-22-10-22-22 0-12 10-22 22-22l199 0c12 0 22 10 22 22z"/>
|
|
||||||
<glyph glyph-name="align-left" unicode="d" d="M456 412l-400 0c-13 0-23 10-23 22 0 12 10 22 23 22l400 0c13 0 23-10 23-22 0-12-10-22-23-22z m-148-97c0 12-10 22-22 22l-230 0c-13 0-23-10-23-22 0-12 10-22 23-22l230 0c12 0 22 10 22 22z m68-119c0 13-10 23-22 23l-298 0c-13 0-23-10-23-23 0-12 10-22 23-22l298 0c12 0 22 10 22 22z m83-118c0 12-10 22-23 22l-379 0c-12 0-22-10-22-22 0-12 10-22 22-22l379 0c13 0 23 10 23 22z"/>
|
|
||||||
<glyph glyph-name="align-right" unicode="e" d="M456 412l-400 0c-13 0-23 10-23 22 0 12 10 22 23 22l400 0c13 0 23-10 23-22 0-12-10-22-23-22z m23-97c0 12-10 22-23 22l-230 0c-12 0-22-10-22-22 0-12 10-22 22-22l230 0c13 0 23 10 23 22z m0-119c0 13-10 23-23 23l-298 0c-12 0-22-10-22-23 0-12 10-22 22-22l298 0c13 0 23 10 23 22z m-2-118c0 12-10 22-22 22l-379 0c-13 0-23-10-23-22 0-12 10-22 23-22l379 0c12 0 22 10 22 22z"/>
|
|
||||||
<glyph glyph-name="anchor" unicode="f" d="M485 215c-5 5-11 8-18 8l-71 0c-13 0-23-10-23-23 0-12 10-22 23-22l43 0c-22-72-85-123-161-132l0 295c37 10 64 44 64 84 0 48-38 87-86 87-48 0-86-39-86-87 0-40 25-74 64-84l0-295c-78 9-139 60-161 132l43 0c13 0 23 10 23 22 0 13-10 23-23 23l-71 0c-7 0-13-3-18-8-4-5-6-11-5-17 20-115 118-198 234-198 116 0 214 83 233 198 1 6 0 12-4 17z m-271 210c0 24 19 42 42 42 23 0 42-18 42-42 0-23-19-42-42-42-23 0-42 19-42 42z"/>
|
|
||||||
<glyph glyph-name="archive" unicode="g" d="M87 390c0 12 10 22 23 22l292 0c12 0 22-10 22-22 0-13-10-23-22-23l-292 0c-13 0-23 10-23 23z m59 55l220 0c10 0 19 9 19 20 0 10-9 19-19 19l-220 0c-10 0-19-9-19-19 0-11 9-20 19-20z m366-81l0-61c0-2-1-4-1-6l-71-259c-3-9-11-16-21-16l-327 0c-10 0-19 7-21 17l-70 258c0 1 0 2-1 4 0 1 0 2 0 3l0 60c0 12 10 22 22 22 13 0 23-10 23-22l0-41 422 0 0 41c0 12 10 22 23 22 12 0 22-10 22-22z m-52-86l-409 0 58-211 292 0z m-270-111l132 0c12 0 22 10 22 22 0 12-10 22-22 22l-132 0c-12 0-22-10-22-22 0-12 10-22 22-22z"/>
|
|
||||||
<glyph glyph-name="arrow-down" unicode="h" d="M444 236c-4 8-12 14-21 14l-72 0 0 206c0 13-13 23-25 23l-140 0c-12 0-25-10-25-23l0-206-72 0c-9 0-17-6-21-14-3-8-1-18 5-25l167-170c4-5 10-7 16-7 6 0 12 2 16 7l167 170c6 7 8 17 5 25z m-188-146l-114 116 44 0c13 0 20 8 20 20l0 208 100 0 0-208c0-12 7-20 20-20l44 0z"/>
|
|
||||||
<glyph glyph-name="arrow-left" unicode="i" d="M456 351l-206 0 0 72c0 9-6 17-14 21-8 3-18 1-25-5l-170-167c-5-4-8-10-8-16 0-6 3-12 7-16l170-167c5-4 10-6 16-6 3 0 7 0 9 1 9 4 15 12 15 21l0 72 206 0c12 0 22 13 22 25l0 140c1 12-9 25-22 25z m-22-145l-208 0c-12 0-20-7-20-20l0-44-116 114 116 114 0-44c0-13 8-20 20-20l208 0z"/>
|
|
||||||
<glyph glyph-name="arrow-right" unicode="j" d="M472 272l-170 167c-7 6-18 8-25 5-9-4-15-12-15-21l0-72-206 0c-13 0-23-13-23-25l0-140c0-12 10-25 23-25l206 0 0-72c0-9 6-17 14-21 3-1 6-1 9-1 6 0 12 2 16 6l170 167c4 4 6 10 6 16 0 6-1 12-5 16z m-166-130l0 44c0 13-8 20-20 20l-208 0 0 100 208 0c12 0 20 7 20 20l0 44 116-114z"/>
|
|
||||||
<glyph glyph-name="arrow-thin-down" unicode="k" d="M411 190l-139-139c-5-4-10-6-16-6-6 0-11 2-16 6l-139 139c-9 9-9 23 0 31 9 9 23 9 32 0l101-101 0 325c0 12 10 22 22 22 12 0 22-10 22-22l0-325 102 101c8 9 22 9 31 0 9-8 9-22 0-31z"/>
|
|
||||||
<glyph glyph-name="arrow-thin-left" unicode="l" d="M467 256c0-12-10-22-22-22l-325 0 101-102c9-8 9-22 0-31-4-4-10-6-16-6-5 0-11 2-15 6l-139 139c-9 9-9 23 0 32l139 139c9 9 23 9 31 0 9-9 9-23 0-32l-101-101 325 0c12 0 22-10 22-22z"/>
|
|
||||||
<glyph glyph-name="arrow-thin-right" unicode="m" d="M461 240l-139-139c-4-4-10-6-15-6-6 0-11 2-16 6-9 9-9 23 0 32l101 101-325 0c-12 0-22 10-22 22 0 12 10 22 22 22l325 0-101 102c-9 8-9 22 0 31 8 9 22 9 31 0l139-139c9-9 9-23 0-32z"/>
|
|
||||||
<glyph glyph-name="arrow-thin-up" unicode="n" d="M411 291c-5-5-10-7-16-7-5 0-11 2-15 7l-102 101 0-325c0-12-10-22-22-22-12 0-22 10-22 22l0 325-102-101c-8-9-22-9-31 0-9 8-9 22 0 31l139 139c9 9 23 9 31 0l139-139c10-9 10-23 1-31z"/>
|
|
||||||
<glyph glyph-name="arrow-up" unicode="o" d="M439 302l-167 170c-4 4-10 7-16 7-6 0-12-3-16-7l-167-170c-6-6-8-18-5-25 4-9 12-15 21-15l72 0 0-206c0-12 13-22 25-22l140 0c12 0 25 10 25 22l0 206 72 0c9 0 17 6 21 14 3 8 1 19-5 26z m-113 4c-13 0-20-8-20-20l0-208-100 0 0 208c0 12-7 20-20 20l-44 0 114 116 114-116z"/>
|
|
||||||
<glyph glyph-name="article" unicode="p" d="M423 501l-334 0c-12 0-22-10-22-22l0-446c0-12 10-22 22-22l334 0c12 0 22 10 22 22l0 446c0 12-10 22-22 22z m-22-445l-290 0 0 400 290 0z m-234 80c0 11 9 20 19 20l133 0c10 0 19-9 19-20 0-10-8-19-19-19l-133 0c-10 0-19 9-19 19z m0 78c0 11 9 20 19 20l133 0c10 0 19-9 19-20 0-10-8-19-19-19l-133 0c-10 0-19 9-19 19z m172 162c0 10-8 19-19 19l-134 0c-10 0-19-9-19-19l0-78c0-11 9-20 19-20l134 0c11 0 19 9 19 20z m-133-20l95 0 0-39-95 0z"/>
|
|
||||||
<glyph glyph-name="backspace" unicode="q" d="M512 258l0-98c0-14-8-25-22-25-14 0-23 11-23 25l0 73-380 0 57-56c10-9 9-25-1-35-5-5-12-7-18-7-6 0-13 2-18 7l-100 98c-4 5-7 12-7 18 0 7 3 13 7 17l100 99c9 9 25 9 35 0 9-9 9-25-1-35l-56-56 401 0c7 0 14-3 19-8 4-4 7-11 7-17z"/>
|
|
||||||
<glyph glyph-name="basket" unicode="r" d="M490 351l-61 0c0 0-1 1-1 2l-105 128c-8 10-22 12-31 4-10-8-12-23-4-33l83-101-230 0 83 101c8 10 6 24-4 32-9 8-23 7-31-3l-105-129c0 0-1-1-1-1l-61 0c-12 0-22-8-22-20l0-84c0-12 10-24 22-24l7 0 42-170c5-19 22-31 42-31l286 0c20 0 37 13 42 31l42 170 7 0c12 0 22 12 22 24l0 84c0 12-10 20-22 20z m-445-45l422 0 0-39-422 0z m353-239l-284 0-39 156 362 0z"/>
|
|
||||||
<glyph glyph-name="basketball" unicode="s" d="M256 512c-141 0-256-115-256-256 0-141 115-256 256-256 141 0 256 115 256 256 0 141-115 256-256 256z m161-392c-14 13-38 41-47 84 43 6 75 15 95 22-5-40-23-76-48-106z m-370 107c20-8 52-17 95-23-8-43-33-71-47-84-25 30-43 66-48 107z m35 149c18-19 56-67 62-127-54 8-86 20-99 26 4 37 17 72 37 101z m384-101c-12-6-44-18-98-26 5 60 44 108 62 127 20-29 33-64 36-101z m-143-31c-14-1-29-2-45-2l0 224c48-5 90-25 123-56-21-22-74-84-78-166z m-89-3c-16 1-31 1-45 2-4 83-58 145-78 167 33 30 75 51 122 56l0-225z m-48-42c15-1 30-2 48-2l0-151c-40 4-77 20-108 43 20 19 50 55 60 110z m92-3c17 1 33 2 48 3 10-55 40-92 60-111-30-23-68-38-108-43z"/>
|
|
||||||
<glyph glyph-name="battery-empty" unicode="t" d="M490 317l-17 0 0 61c0 13-9 23-22 23l-429 0c-12 0-22-10-22-23l0-244c0-13 10-23 22-23l429 0c12 0 22 10 22 23l0 61 17 0c12 0 22 8 22 20l0 82c0 12-10 20-22 20z m-61-161l-384 0 0 200 384 0z"/>
|
|
||||||
<glyph glyph-name="battery-full" unicode="u" d="M195 211l0 90c0 12 10 22 22 22l39 0c12 0 22-10 22-22l0-90c0-12-10-22-22-22l-39 0c-12 0-22 10-22 22z m139-22l39 0c12 0 22 10 22 22l0 57c0 6-1 11-5 15l-29 33c-5 5-10 7-17 7l-10 0c-12 0-22-9-22-21l0-91c0-12 10-22 22-22z m-234 0l39 0c12 0 22 10 22 22l0 90c0 12-10 22-22 22l-39 0c-12 0-22-10-22-22l0-90c0-12 10-22 22-22z m412 108l0-82c0-12-10-20-22-20l-17 0 0-61c0-13-9-23-22-23l-429 0c-12 0-22 10-22 23l0 244c0 13 10 23 22 23l429 0c12 0 22-10 22-23l0-61 17 0c12 0 22-8 22-20z m-83 59l-384 0 0-200 384 0z"/>
|
|
||||||
<glyph glyph-name="battery-low" unicode="v" d="M490 317l-17 0 0 61c0 13-9 23-22 23l-429 0c-12 0-22-10-22-23l0-244c0-13 10-23 22-23l429 0c12 0 22 10 22 23l0 61 17 0c12 0 22 8 22 20l0 82c0 12-10 20-22 20z m-61-161l-384 0 0 200 384 0z m-268 55c0-12-10-22-22-22l-39 0c-12 0-22 10-22 22l0 90c0 12 10 22 22 22l39 0c12 0 22-10 22-22z"/>
|
|
||||||
<glyph glyph-name="battery-medium" unicode="w" d="M490 317l-17 0 0 61c0 13-9 23-22 23l-429 0c-12 0-22-10-22-23l0-244c0-13 10-23 22-23l429 0c12 0 22 10 22 23l0 61 17 0c12 0 22 8 22 20l0 82c0 12-10 20-22 20z m-61-161l-384 0 0 200 384 0z m-268 55c0-12-10-22-22-22l-39 0c-12 0-22 10-22 22l0 90c0 12 10 22 22 22l39 0c12 0 22-10 22-22z m117 0c0-12-10-22-22-22l-39 0c-12 0-22 10-22 22l0 90c0 12 10 22 22 22l39 0c12 0 22-10 22-22z"/>
|
|
||||||
<glyph glyph-name="bell" unicode="x" d="M467 114c-37 0-51 22-51 158 0 107-49 174-132 184l0 34c0 13-10 23-22 23-13 0-23-10-23-23l0-33c-89-7-140-75-140-184 0-137-17-158-54-158-12-1-23-9-23-22 0-12 10-21 23-21l144 0c2-16 7-37 20-51 12-13 28-20 46-20 18 0 34 7 46 20 13 15 19 35 21 51l145 0c13 0 23 9 23 21 0 13-10 21-23 21z m-199-63c-2-3-5-6-13-6-7 0-11 3-13 6-4 5-7 10-8 21l19 0c1 0 2 0 4 0 1 0 2 0 3 0l18 0c-2-11-5-16-10-21z m-9 66c-1 0-2 0-3 0-1 0-2 0-3 0l-132 0c21 39 21 99 21 156 0 91 39 139 111 139l6 0c71 0 111-48 111-139 0-57 0-117 20-156z m79 197c1-10-7-20-18-20-1 0-1 0-1 0-10 0-19 8-20 18-1 25-21 34-23 35-10 5-14 16-11 26 4 10 15 14 26 10 2-1 45-18 47-69z"/>
|
|
||||||
<glyph glyph-name="blog" unicode="y" d="M423 501l-334 0c-12 0-22-10-22-22l0-446c0-12 10-22 22-22l334 0c12 0 22 10 22 22l0 446c0 12-10 22-22 22z m-22-445l-290 0 0 400 290 0z m-242 94c0 13 10 23 22 23l150 0c12 0 22-10 22-23 0-12-10-22-22-22l-150 0c-12 0-22 10-22 22z m3 106c0 12 10 22 22 22l147 0c12 0 22-10 22-22 0-12-10-22-22-22l-147 0c-12 0-22 10-22 22z m0 106c0 12 10 22 22 22l147 0c12 0 22-10 22-22 0-13-10-23-22-23l-147 0c-12 0-22 10-22 23z"/>
|
|
||||||
<glyph glyph-name="bluetooth" unicode="z" d="M289 256l99 99c9 8 9 22 0 31l-116 119c-7 7-16 9-24 5-9-3-14-11-14-20l0-179-79 78c-9 9-23 8-32 0-9-9-8-23 0-32l103-101-102-102c-9-9-9-23 0-32 4-4 10-6 15-6 6 0 11 2 16 6l79 79 0-179c0-9 5-17 14-20 2-1 5-2 8-2 6 0 12 2 16 7l117 119c8 9 8 23 0 31z m-11 179l63-64-63-63z m0-358l0 127 63-63z"/>
|
|
||||||
<glyph glyph-name="bold" unicode="A" d="M334 266c21 20 34 48 34 79 0 61-50 111-111 111l-118 0c-12 0-22-10-22-22l0-356c0-12 10-22 22-22l145 0c61 0 111 50 111 111 0 43-24 80-61 99z m-173 146l96 0c36 0 66-30 66-67 0-37-30-67-66-67l-96 0z m123-312l-123 0 0 134 123 0c37 0 67-30 67-67 0-37-30-67-67-67z"/>
|
|
||||||
<glyph glyph-name="bookmark" unicode="B" d="M356 512l-200 0c-12 0-22-10-22-22l0-468c0-9 5-17 13-20 3-1 6-2 9-2 6 0 12 2 16 7l82 87 86-87c6-6 16-8 25-5 8 3 13 11 13 20l0 468c0 12-10 22-22 22z m-22-436l-65 66c-4 5-10 8-15 8-6 0-12-4-16-8l-60-64 0 389 156 0z"/>
|
|
||||||
<glyph glyph-name="bookmarks" unicode="C" d="M295 417l-161 0c-13 0-23-8-23-20l0-375c0-9 6-17 14-20 3-1 6-2 9-2 6 0 11 2 16 7l63 66 66-67c6-6 16-8 24-5 9 4 14 12 14 21l0 375c0 12-10 20-22 20z m-22-341l-45 45c-4 5-10 7-15 7-7 0-12-3-17-7l-40-43 0 295 117 0z m122 419l0-374c0-11-9-20-19-20-11 0-20 9-20 20l0 352-117 0 0-7c0-11-9-20-19-20-11 0-20 9-20 20l0 29c0 11 6 17 17 17l161 0c11 0 17-6 17-17z"/>
|
|
||||||
<glyph glyph-name="box" unicode="D" d="M416 378l-320 0c-12 0-22-10-22-22l-3-284c0-6 2-11 6-16 5-4 10-6 16-6l325 0c6 0 12 2 16 6 4 5 6 10 6 16l-2 284c0 12-10 22-22 22z m-160-283l-141 0 3 239 275 0 2-239z m71 178c0-13-10-23-22-23l-98 0c-12 0-22 10-22 23 0 12 10 22 22 22l97 0c13 0 23-10 23-22z m167 89c-1 0-3 0-4 0-11 0-20 7-22 18l-7 37-410 0-7-37c-2-13-14-20-26-18-12 2-20 14-18 26l11 56c2 10 11 18 22 18l446 0c10 0 20-8 21-18l11-56c3-12-5-23-17-26z"/>
|
|
||||||
<glyph glyph-name="briefcase" unicode="E" d="M505 385c-4 3-9 5-15 5l-117 0 0 66c0 13-11 23-24 23l-186 0c-13 0-24-10-24-23l0-66-117 0c-12 0-22-8-22-20l0-314c0-13 10-23 22-23l468 0c12 0 22 10 22 23l0 313c0 6-2 11-7 16z m-321 49l144 0 0-44-144 0z m283-89l0-117-155 0 0 9c0 9-9 13-19 13l-74 0c-10 0-19-5-19-13l0-9-155 0 0 117z m-189-128l0-11-44 0 0 11z m-233-139l0 117 155 0 0-6c0-9 9-16 19-16l75 0c9 0 18 7 18 16l0 6 156 0 0-117z"/>
|
|
||||||
<glyph glyph-name="brightness-low" unicode="F" d="M256 352c-53 0-96-43-96-96 0-53 43-96 96-96 53 0 96 43 96 96 0 53-43 96-96 96z m0-148c-28 0-52 24-52 52 0 28 24 52 52 52 28 0 52-24 52-52 0-28-24-52-52-52z m-22 204l0 21c0 12 10 22 22 22 12 0 22-10 22-22l0-21c0-12-10-22-22-22-12 0-22 10-22 22z m217-152c0-12-10-22-22-22l-21 0c-12 0-22 10-22 22 0 12 10 22 22 22l21 0c12 0 22-10 22-22z m-173-152l0-21c0-12-10-22-22-22-12 0-22 10-22 22l0 21c0 12 10 22 22 22 12 0 22-10 22-22z m-174 130l-21 0c-12 0-22 10-22 22 0 12 10 22 22 22l21 0c12 0 22-10 22-22 0-12-10-22-22-22z m244 114c-9 9-9 23 0 32l14 13c9 9 23 9 31 0 9-8 9-22 0-31l-13-14c-5-5-10-7-16-7-6 1-12 3-16 7z m45-198c9-9 9-23 0-32-4-4-10-7-15-7-6 0-11 3-16 7l-14 14c-9 9-9 23 0 32 9 9 23 9 32 0z m-229 14c9-9 9-23 0-32l-14-13c-4-5-10-7-15-7-6 0-11 2-16 7-9 8-9 22 0 31l14 14c8 9 22 9 31 0z m-45 198c-9 9-9 23 0 32 8 9 22 9 31 0l14-14c9-9 9-23 0-32-4-4-10-6-15-6-6 0-12 2-16 6z"/>
|
|
||||||
<glyph glyph-name="brightness-max" unicode="G" d="M256 380c-68 0-124-56-124-124 0-68 56-124 124-124 68 0 124 56 124 124 0 68-56 124-124 124z m0-204c-44 0-80 36-80 80 0 44 36 80 80 80 44 0 80-36 80-80 0-44-36-80-80-80z m-22 268l0 46c0 12 10 22 22 22 12 0 22-10 22-22l0-46c0-13-10-23-22-23-12 0-22 10-22 23z m278-188c0-12-10-22-22-22l-46 0c-13 0-23 10-23 22 0 12 10 22 23 22l46 0c12 0 22-10 22-22z m-234-188l0-46c0-12-10-22-22-22-12 0-22 10-22 22l0 46c0 13 10 23 22 23 12 0 22-10 22-23z m-210 166l-46 0c-12 0-22 10-22 22 0 12 10 22 22 22l46 0c13 0 23-10 23-22 0-12-10-22-23-22z m305 139c-9 9-9 23 0 32l32 32c9 9 23 9 32 0 9-9 9-23 0-32l-32-32c-5-5-10-7-16-7-6 0-12 2-16 7z m64-267c9-9 9-23 0-31-5-5-10-7-16-7-5 0-11 2-15 7l-33 32c-9 9-9 23 0 32 9 9 23 9 32 0z m-298 33c9-9 9-23 0-32l-32-32c-5-4-10-7-16-7-5 0-11 3-15 7-9 9-9 23 0 32l32 32c8 8 22 8 31 0z m-64 267c-9 9-9 23 0 31 9 9 23 9 32 0l32-32c9-9 9-23 0-32-4-4-10-6-15-6-6 0-12 2-16 6z"/>
|
|
||||||
<glyph glyph-name="brightness-medium" unicode="H" d="M256 380c-68 0-124-56-124-124 0-68 56-124 124-124 68 0 124 56 124 124 0 68-56 124-124 124z m-80-124c0 44 36 80 80 80l0-159c-44-1-80 35-80 79z m58 188l0 46c0 12 10 22 22 22 12 0 22-10 22-22l0-46c0-13-10-23-22-23-12 0-22 10-22 23z m278-188c0-12-10-22-22-22l-46 0c-13 0-23 10-23 22 0 12 10 22 23 22l46 0c12 0 22-10 22-22z m-234-188l0-46c0-12-10-22-22-22-12 0-22 10-22 22l0 46c0 13 10 23 22 23 12 0 22-10 22-23z m-210 166l-46 0c-12 0-22 10-22 22 0 12 10 22 22 22l46 0c13 0 23-10 23-22 0-12-10-22-23-22z m305 139c-9 9-9 23 0 32l32 32c9 9 23 9 32 0 9-9 9-23 0-32l-32-32c-5-5-10-7-16-7-6 1-12 2-16 7z m64-267c9-9 9-23 0-31-5-5-10-7-16-7-5 0-11 2-15 7l-33 32c-9 9-9 23 0 32 9 9 23 9 32 0z m-298 33c9-9 9-23 0-32l-32-32c-5-4-10-7-16-7-5 0-11 3-15 7-9 9-9 23 0 32l32 32c8 8 22 8 31 0z m-64 267c-9 9-9 23 0 31 9 9 23 9 32 0l32-32c9-9 9-23 0-32-4-4-10-6-15-6-6 0-12 2-16 6z"/>
|
|
||||||
<glyph glyph-name="broadcast" unicode="I" d="M509 321c-5 17-15 30-30 38-19 10-41 9-57 6l-32 114c-2 8-8 14-16 16-8 1-16-1-22-7-79-89-112-111-200-149l-69-20c-61-17-96-82-79-143 9-29 28-54 56-69 17-10 36-15 55-15 9 0 18 1 27 4l7-26c4-14 12-27 22-37l12-11c4-4 10-6 15-6 6 0 12 2 16 7 9 9 9 23-1 32l-12 11c-4 4-7 10-9 16l-7 26 32 9c92 14 134 13 247-19 2-1 4-1 6-1 6 0 12 2 16 7 5 5 8 13 5 21l-32 114c14 6 34 16 45 34 8 15 10 31 5 48z m-428-175c-16 9-28 24-34 42-10 38 11 77 48 88l50 15 23-81 16-56-50-14c-18-5-37-3-53 6z m227 24c-25 0-50-2-80-6l-32 114-8 28c70 32 108 57 170 123l79-278c-52 14-90 19-129 19z m158 127c-4-6-12-11-20-14l-11 39c9 1 18 1 24-3 3-1 6-3 8-10 2-6 0-10-1-12z m-142 36c7-9 5-21-4-27-21-14-44-27-45-28-3-1-6-2-9-2-7 0-14 4-17 11-5 9-1 21 8 26 0 0 22 11 40 24 9 7 21 5 27-4z"/>
|
|
||||||
<glyph glyph-name="browser" unicode="J" d="M490 462l-468 0c-12 0-22-10-22-22l0-368c0-12 10-22 22-22l468 0c12 0 22 10 22 22l0 368c0 12-10 22-22 22z m-23-95l-155 0 0 50 155 0z m-333 0l0 50 55 0 0-50z m89 50l55 0 0-50-55 0z m-123 0l0-50-55 0 0 50z m-55-322l0 233 422 0 0-233z"/>
|
|
||||||
<glyph glyph-name="browser-upload" unicode="K" d="M278 250l1-228c0-12-10-22-22-22-13 0-23 10-23 22l0 229-65-65c-9-8-23-8-32 0-8 9-8 23 0 32l103 102c9 8 23 8 31 0l102-102c9-9 9-23 0-32-4-4-10-6-15-6-6 0-11 2-16 6z m234 240l0-371c0-13-10-24-22-24l-137 0c-12 0-22 10-22 22 0 12 10 22 22 22l114 0 0 239-422 0 0-239 116 0c12 0 22-10 22-22 0-12-10-22-22-22l-139 0c-12 0-22 11-22 24l0 371c0 12 10 22 22 22l468 0c12 0 22-10 22-22z m-289-73l55 0 0 50-55 0z m-34 50l-55 0 0-50 55 0z m-144-50l55 0 0 50-55 0z m422 0l0 50-155 0 0-50z"/>
|
|
||||||
<glyph glyph-name="brush" unicode="L" d="M512 464c0 12-5 24-14 33l-1 1c-18 18-48 18-66 1l-272-252c-37 7-76-3-104-31-38-38-38-80-37-106 0-3 0-6 0-9-1-21-11-46-16-54-3-6-3-12-1-18 2-6 7-11 12-13 27-11 53-16 78-16 44 0 85 17 117 48 26 27 41 58 41 90 0 8-1 15-2 22l251 271c9 9 14 20 14 33z m-335-384c-33-33-78-43-125-30 5 14 10 32 10 50 0 4 0 7 0 11 0 23-1 49 24 73 27 27 71 27 98 0 14-13 21-29 21-46 0-19-10-40-28-58z m290 382c0 0-1-1-1-1l-239-257c-4 4-7 8-11 12-4 4-8 7-12 11l257 239c0 0 1 1 1 1 1 1 3 1 4 0l1-1c0-1 0-2 0-2 0-1 0-2 0-2z"/>
|
|
||||||
<glyph glyph-name="calendar" unicode="M" d="M122 391l0 71c0 15 13 28 28 28 16 0 28-13 28-28l0-71c0-16-12-28-28-28-15 0-28 12-28 28z m240-28c15 0 28 12 28 28l0 71c0 15-13 28-28 28-16 0-28-13-28-28l0-71c0-16 12-28 28-28z m150 63l0-376c0-12-10-22-22-22l-468 0c-12 0-22 10-22 22l0 376c0 13 10 25 22 25l52 0c12 0 22-10 22-22 0-13-10-23-22-23l-29 0 0-94 422 0 0 94-29 0c-12 0-22 10-22 23 0 12 10 22 22 22l52 0c12 0 22-12 22-25z m-45-354l0 201-422 0 0-201z m-246 334l70 0c12 0 22 10 22 23 0 12-10 22-22 22l-70 0c-12 0-22-10-22-22 0-13 10-23 22-23z"/>
|
|
||||||
<glyph glyph-name="camcorder" unicode="N" d="M500 393c-8 4-18 3-25-2l-91-68 0 50c0 12-8 22-20 22l-342 0c-12 0-22-10-22-22l0-234c0-12 10-22 22-22l342 0c12 0 20 10 20 22l0 50 91-68c4-2 10-4 14-4 4 0 7 0 10 2 8 4 13 12 13 20l0 234c0 8-5 16-12 20z m-161-232l-294 0 0 190 294 0z m128 23l-77 59 0 26 77 59z"/>
|
|
||||||
<glyph glyph-name="camera" unicode="O" d="M256 362c-70 0-127-58-127-129 0-72 57-129 127-129 70 0 127 57 127 129 0 71-57 129-127 129z m0-215c-46 0-83 38-83 85 0 47 37 85 83 85 46 0 83-38 83-84 0-47-37-86-83-86z m62 80c-1-10-10-17-20-17-1 0-1 0-2 0-11 2-19 11-17 22 2 16-17 25-18 26-9 4-14 16-9 25 4 10 15 14 25 10 18-8 46-30 41-66z m-43-24c4-4 7-10 7-16 0-6-3-12-7-16-5-3-10-6-16-6-5 0-11 2-15 6-4 5-7 10-7 16 0 6 2 12 7 16 4 4 10 6 15 6 6 0 12-2 16-6z m215 164l-86 0-24 89c-3 10-12 17-22 17l-205 0c-10 0-19-7-22-17l-24-89-85 0c-12 0-22-9-22-21l0-285c0-12 10-22 22-22l468 0c12 0 22 10 22 22l0 285c0 12-10 21-22 21z m-23-284l-422 0 0 240 80 0c10 0 19 7 21 16l24 90 172 0 24-90c2-9 11-16 21-16l80 0z"/>
|
|
||||||
<glyph glyph-name="card" unicode="P" d="M512 382c0 23-18 41-41 41l-430 0c-23 0-41-18-41-41l0-252c0-23 18-41 41-41l430 0c23 0 42 18 42 41l0 252z m-45-4l0-39-422 0 0 39z m-422-244l0 139 422 0 0-139z m381 72c0-12-10-22-23-22l-105 0c-13 0-23 10-23 22 0 12 10 22 23 22l105 0c13 0 23-10 23-22z"/>
|
|
||||||
<glyph glyph-name="cart" unicode="Q" d="M511 360l-60-187c-4-14-16-23-30-23l-230 0c-13 0-26 9-30 21l-88 235-51 0c-12 0-22 10-22 23 0 12 10 22 22 22l66 0c10 0 18-6 22-15l90-241 212 0 47 150-262 0c-12 0-22 10-22 22 0 13 10 23 22 23l293 0c7 0 14-4 18-10 4-5 5-13 3-20z m-308-239c-10 0-19-4-26-11-7-6-11-16-11-25 0-10 4-19 11-26 7-7 16-11 26-11 9 0 18 4 25 11 7 7 11 16 11 26 0 9-4 19-11 25-7 7-16 11-25 11z m199 0c-9 0-19-4-25-11-7-6-11-16-11-25 0-10 4-19 11-26 6-7 16-11 25-11 10 0 19 4 26 11 7 7 11 16 11 26 0 9-4 19-11 25-7 7-16 11-26 11z"/>
|
|
||||||
<glyph glyph-name="checklist" unicode="R" d="M201 434c0 16 13 28 28 28l244 0c16 0 28-12 28-28 0-15-12-28-28-28l-244 0c-15 0-28 13-28 28z m272-150l-244 0c-15 0-28-12-28-28 0-16 13-28 28-28l244 0c16 0 28 12 28 28 0 16-12 28-28 28z m0-178l-244 0c-15 0-28-13-28-28 0-16 13-28 28-28l244 0c16 0 28 12 28 28 0 15-12 28-28 28z m-334 370c0 10-9 19-19 19l-84 0c-10 0-19-9-19-19l0-84c0-10 9-19 19-19l84 0c10 0 19 9 19 19z m0-262c0-10-9-19-19-19l-84 0c-10 0-19 9-19 19l0 84c0 10 9 19 19 19l84 0c10 0 19-9 19-19z m-33 64l-50 0 0-44 50 0z m33-242c0-10-9-19-19-19l-84 0c-10 0-19 9-19 19l0 84c0 10 9 19 19 19l84 0c10 0 19-9 19-19z m-33 64l-50 0 0-50 50 0z"/>
|
|
||||||
<glyph glyph-name="checkmark" unicode="S" d="M191 111c-6 0-12 3-17 8l-111 110c-10 10-10 26 0 36 10 10 25 10 36 0l93-93 222 221c10 10 26 10 36 0 10-10 10-25 0-35l-240-239c-6-5-12-8-19-8z"/>
|
|
||||||
<glyph glyph-name="chevron-down" unicode="T" d="M256 161c-6 0-12 3-16 7l-139 145c-9 9-9 23 0 31 9 9 23 9 32 0l123-128 123 128c8 9 23 9 32 0 9-8 9-22 0-31l-139-145c-4-4-10-7-16-7z"/>
|
|
||||||
<glyph glyph-name="chevron-left" unicode="U" d="M344 133c9-8 9-23 0-32-4-4-10-6-16-6-5 0-11 2-15 6l-145 139c-4 4-7 10-7 16 0 6 3 12 7 16l145 139c9 9 23 9 31 0 9-9 9-23 0-32l-128-123z"/>
|
|
||||||
<glyph glyph-name="chevron-right" unicode="V" d="M351 256c0-6-3-12-7-16l-145-139c-4-4-10-6-15-6-6 0-12 2-16 6-9 9-9 23 0 32l128 123-128 123c-9 8-9 23 0 32 8 9 22 9 31 0l145-139c4-4 7-10 7-16z"/>
|
|
||||||
<glyph glyph-name="chevron-up" unicode="W" d="M395 161c-6 0-12 3-16 7l-123 128-123-128c-8-9-23-9-32 0-9 8-9 22 0 31l139 145c4 4 10 7 16 7 6 0 12-3 16-7l139-145c9-9 9-23 0-31-5-4-10-7-16-7z"/>
|
|
||||||
<glyph glyph-name="clipboard" unicode="X" d="M429 462l-83 0-9 23c-6 16-22 27-39 27l-79 0c-18 0-33-11-39-27l-9-23-88 0c-12 0-22-11-22-23l0-417c0-12 10-22 22-22l346 0c12 0 22 10 22 22l0 417c0 12-10 23-22 23z m-242-45c9 0 18 6 21 14l13 36 75 0 13-36c4-9 12-14 22-14l17 0-16-31c-3-5-8-8-13-8l-121 0c-5 0-10 3-13 7l-19 32z m219-372l-300 0 0 372 9 0 31-55c0-1 1 0 1-1 11-17 30-27 51-27l120 0c21 0 42 10 52 29 0 1 1 2 1 2l26 52 9 0z"/>
|
|
||||||
<glyph glyph-name="clock" unicode="Y" d="M256 512c-141 0-256-115-256-256 0-141 115-256 256-256 141 0 256 115 256 256 0 141-115 256-256 256z m0-467c-117 0-211 94-211 211 0 117 94 211 211 211 117 0 211-94 211-211 0-117-94-211-211-211z m85 158c9-9 9-23 0-32-4-5-10-7-15-7-6 0-12 2-16 7l-70 69c-4 4-6 10-6 16l0 132c0 13 10 23 22 23 12 0 22-10 22-23l0-123z"/>
|
|
||||||
<glyph glyph-name="clockwise" unicode="Z" d="M484 279l-78-78c-4-4-10-6-16-6-6 0-12 2-16 6l-77 78c-8 9-8 23 0 32 9 8 23 8 32 0l43-43c-6 80-72 144-153 144-84 0-152-70-152-156 0-86 68-156 153-156 31 0 61 10 86 27 10 8 24 5 31-5 7-10 5-24-5-31-33-23-72-35-112-35-109 0-198 89-198 200 0 111 89 200 198 200 102 0 187-79 196-181l35 36c9 8 23 8 32 0 9-9 9-23 1-32z"/>
|
|
||||||
<glyph glyph-name="cloud" unicode="0" d="M396 78c-111 0-294 0-297 0-49 0-90 37-98 88-6 39 11 92 73 120-14 62 21 114 67 136 30 14 62 15 92 5 26-8 50-26 68-51 27 15 60 16 87 1 24-13 46-41 43-83 60-19 84-70 81-115-4-49-41-101-116-101z m-202 312c-12 0-24-3-34-8-33-15-58-53-38-101 2-6 2-12-1-18-2-5-7-10-13-11-66-21-65-66-63-79 4-25 23-50 54-50 1 0 185-1 297-1 46 0 69 30 71 61 3 30-16 65-64 71-6 1-12 5-15 10-3 5-5 11-3 18 6 26-1 47-18 57-15 8-38 8-57-11-5-5-12-7-19-6-7 1-13 5-16 11-22 42-53 57-81 57z"/>
|
|
||||||
<glyph glyph-name="cloud-download" unicode="1" d="M506 265c-3-48-40-99-113-99-33 0-50 0-50 0-12 0-22 10-22 23 0 12 10 22 22 22 0 0 17 0 50 0 45 0 67 28 69 57 3 30-16 63-62 69-7 1-12 5-15 10-4 5-5 11-4 18 6 25 0 45-16 54-14 8-37 8-56-11-5-5-12-7-18-6-7 1-13 6-17 12-31 58-79 62-111 47-31-15-55-51-36-96 2-6 2-13-1-18-2-6-7-10-13-12-66-21-64-64-62-76 3-24 22-48 51-48l68 0c13 0 23-10 23-22 0-13-10-22-23-22l-68 0c-47 0-88 36-95 85-6 39 10 90 70 117-13 60 20 110 66 131 47 23 112 16 156-44 28 15 60 16 87 1 22-13 43-40 41-81 58-18 82-68 79-111z m-174-135l-54-54 0 202c0 12-10 23-23 23-12 0-22-11-22-23l1-202-54 54c-9 9-23 9-32 0-9-9-9-23 0-31l92-93c4-4 10-7 15-7 6 0 12 3 16 7l92 92c9 9 9 23 0 32-8 9-22 9-31 0z"/>
|
|
||||||
<glyph glyph-name="cloud-upload" unicode="2" d="M512 225c-3-48-41-101-115-101-34 0-52 0-52 0-12 0-22 10-22 22 0 12 10 21 22 21 0 0 18 1 52 1 46 0 69 31 71 61 2 30-17 64-65 71-6 1-11 4-15 9-3 5-4 12-3 18 6 26 0 47-18 56-14 9-38 8-56-10-5-5-13-7-19-6-7 1-13 5-17 11-32 61-81 64-114 48-32-15-57-52-37-99 2-6 2-13-1-18-3-6-8-10-13-12-68-20-67-65-65-78 4-25 23-50 54-50l69 0c12 0 22-11 22-23 0-12-10-24-22-24l-69 2c-49 0-90 38-97 89-6 39 10 91 73 119-15 61 20 113 66 134 48 23 116 17 160-45 28 15 61 16 88 1 23-14 45-41 42-83 59-18 84-69 81-114z m-178-18c5-4 10-7 16-7 6 0 11 3 16 7 9 9 9 23 0 32l-94 94c-4 4-10 6-16 6-6 0-12-2-16-6l-94-95c-9-9-9-23 0-32 9-8 23-8 32 0l56 58 0-208c0-13 10-23 23-23 12 0 22 10 22 23l-1 207z"/>
|
|
||||||
<glyph glyph-name="code" unicode="3" d="M328 95c-6 0-11 2-16 6-8 9-8 23 1 32l128 123-128 123c-9 8-9 23-1 32 9 9 23 9 32 0l145-139c4-4 6-10 6-16 0-6-2-12-6-16l-145-139c-5-4-10-6-16-6z m-128 6c8 9 8 23-1 32l-128 123 128 123c9 8 9 23 1 32-9 9-23 9-32 0l-145-139c-4-4-6-10-6-16 0-6 2-12 6-16l145-139c5-4 10-6 16-6 5 0 11 2 16 6z"/>
|
|
||||||
<glyph glyph-name="contract" unicode="4" d="M492 49c9-9 9-23 0-32-4-4-10-6-16-6-5 0-11 2-16 6l-121 121 0-57c0-13-10-23-22-23-12 0-22 10-22 23l0 111c0 6 3 12 7 16 4 3 10 6 16 6l111 0c12 0 22-10 22-22 0-12-10-22-22-22l-57 0z m-175 246l111 0c12 0 22 10 22 22 0 12-10 22-22 22l-57 0 123 124c9 9 9 23 0 31-9 9-23 9-31 0l-124-123 0 57c0 12-10 23-22 23-12 0-22-10-22-22l0-112c0-6 2-11 7-15 4-5 9-7 15-7z m-123 154c-12 0-21-10-21-22l0-57-123 123c-9 8-23 8-32 0-9-9-9-23 0-31l122-122-57 0 0-1c-11 0-22-10-22-22 0-13 10-23 22-23l111 0c6 0 11 3 16 7 4 5 6 10 6 16l0 111c0 11-10 21-22 21z m-1-232l-111 0c-12 0-22-10-22-22 0-12 10-22 22-22l57 0-121-123c-9-9-9-23 0-32 4-4 10-6 16-6 6 0 12 2 17 6l122 121 0-57c0-12 8-21 21-21l-1 0c12 0 22 9 22 21l0 111c0 6-2 12-6 17-4 4-10 7-16 7z"/>
|
|
||||||
<glyph glyph-name="contract-2" unicode="5" d="M225 227c4-5 7-11 7-17l0-116c0-12-10-21-22-21l0 0c-12 0-21 8-21 20l0 63-139-138c-4-5-11-7-17-7-5 0-11 2-15 7-9 9-9 23 0 32l138 139-63 0c-12 0-22 10-22 22 0 13 10 23 22 23l117 0c6 0 11-3 15-7z m269 267c-9 9-22 9-31 0l-140-141 0 64c0 12-10 23-23 23-12 0-22-10-22-23l0-116c0-7 2-12 6-16 5-5 10-6 16-6l117 0c12 0 22 10 22 22 0 12-10 22-22 22l-64 0 141 140c9 9 9 23 0 31z"/>
|
|
||||||
<glyph glyph-name="conversation" unicode="6" d="M490 378l-217 0 0 52c0 9-13 21-21 21l-235 0c-10 0-17-12-17-21l0-143c0-9 8-20 17-20l34 0 44-48c4-4 8-5 13-5 2 0 3 0 5 1 7 3 10 9 10 17l0 35 33 0 0-103c0-13 13-25 25-25l153 0 0-68c0-9 4-17 13-20 3-1 5-2 8-2 6 0 12 1 16 6l83 84 36 0c12 0 22 12 22 25l0 187c0 12-10 27-22 27z m-382-77c-9 0-19-4-19-14l0-11-19 21c-3 4-7 4-12 4l-25 0 0 116 201 0 0-39-53 0c-12 0-25-15-25-27l0-50z m359-117l-22 0c-6 0-11-1-16-6l-51-51 0 37c0 12-11 20-23 20l-155 0 0 150 267 0z m-234 100c0 9 7 17 16 17l107 0c9 0 16-8 16-17 0-10-7-17-16-17l-107 0c-9 0-16 7-16 17z m162-12c-4 3-5 7-5 12 0 4 1 9 5 12 6 6 17 6 24 0 3-4 5-8 5-12 0-5-2-9-5-12-4-3-8-5-12-5-5 1-10 2-12 5z"/>
|
|
||||||
<glyph glyph-name="copy" unicode="7" d="M256 390c-4 4-9 5-14 5l-166 0c-11 0-26-7-26-17l0-352c0-12 15-25 26-25l263 0c12 0 17 14 17 25l0 253c0 5 0 10-4 14z m55-112l-72 0 0 72z m-216-233l0 311 105 0 0-96c0-11 10-21 21-21l96 0 0-194z m364 367l-97 97c-4 2-7 3-11 3l-167 0c-9 0-17-5-17-14l0-53c0-10 7-17 17-17 9 0 16 8 16 17l0 34 117 0 0-94c0-10 8-18 17-18l95 0 0-206-23 0c-10 0-17-7-17-16 0-10 8-17 17-17l42 0c9 0 14 8 14 18l0 254c0 4-1 8-3 12z m-108 61l71-72-71 0z"/>
|
|
||||||
<glyph glyph-name="crop" unicode="8" d="M494 457c9 9 9 23 0 32-8 9-23 9-32 0l-66-66-279 0 0 41c0 12-10 22-22 22-13 0-23-10-23-22l0-41-39 0c-12 0-22-10-22-22 0-13 10-23 22-23l39 0 0-277c0-1 1-1 1-2 0-1 0-2 0-3 0 0 1-1 1-2 0-1 1-2 1-2 0-1 0-1 1-2 0-1 0-2 1-2 0-1 1-2 1-2 1-1 1-1 2-1 1-2 2-2 3-3 0 0 0-1 1-1 1 0 2-1 3-1 1 0 1-1 3-1 0 0 1-1 2-1 1 0 3 0 4 0l288 0 0-39c0-12 10-22 22-22 13 0 23 10 23 22l0 39 38 0c13 0 23 10 23 22 0 12-10 22-23 22l-38 0 0 271z m-143-79l-234-225 0 225z m33-256l-234 0 234 227z"/>
|
|
||||||
<glyph glyph-name="cross" unicode="9" d="M393 154c10-10 10-25 0-35-5-5-11-8-17-8-7 0-13 3-18 8l-102 101-102-101c-5-5-11-8-18-8-6 0-12 3-17 8-10 10-10 25 0 35l101 102-101 102c-10 10-10 25 0 35 10 10 25 10 35 0l102-101 102 101c10 10 25 10 35 0 10-10 10-25 0-35l-101-102z"/>
|
|
||||||
<glyph glyph-name="crosshair" unicode="!" d="M257 512c-1 0-1 0 0 0-1 0-1 0 0 0-142 0-257-115-257-256 0-141 115-256 255-256 142 0 256 115 256 256 1 141-114 256-254 256z m21-466l0 57c0 12-10 22-22 22-12 0-22-10-22-22l0-57c-100 10-178 89-188 188l57 0c12 0 22 10 22 22 0 12-10 22-22 22l-57 0c10 99 88 178 188 188l0-57c0-12 10-22 22-22 12 0 22 10 22 22l0 57c100-10 178-89 188-188l-57 0c-12 0-22-10-22-22 0-12 10-22 22-22l57 0c-10-99-88-178-188-188z"/>
|
|
||||||
<glyph glyph-name="cutlery" unicode=""" d="M461 60c9-9 9-23 0-32-5-4-10-6-16-6-5 0-11 2-15 7l-177 177-175-177c-5-5-10-7-16-7-5 0-11 2-15 7-9 9-9 23 0 32l174 177-30 29-4-4c-14-14-33-22-53-22-20 0-39 8-53 22l-74 73c-9 8-9 22 0 31 9 9 22 9 31 0l74-73c6-6 14-9 22-9 8 0 16 3 22 9l5 5-96 94c-9 9-9 23 0 32 8 9 22 9 31 0l95-95 6 6c12 11 12 31 0 43l-74 73c-9 9-9 23 0 32 9 9 23 9 32 0l73-74c30-29 30-77 0-106l-5-6 29-29 197 199c3 4 10 7 15 7 6 0 12-3 16-7 49-49 41-119-21-181l-76-76c-8-8-22-8-31 0-9 9-9 23 0 32l75 75c45 45 44 79 34 100l-177-180z"/>
|
|
||||||
<glyph glyph-name="device-desktop" unicode="#" d="M470 473l-428 0c-23 0-42-19-42-42l0-247c0-23 19-45 42-45l142 0 0-23-43-34c-7-6-11-17-7-26 3-9 11-17 21-17l200 0c10 0 18 8 22 17 3 9 0 20-7 26l-42 34 0 23 142 0c23 0 42 22 42 45l0 247c0 23-19 42-42 42z m-174-383l13-12-109 0 15 13c4 4 8 10 8 16l0 32 66 0 0-32c0-6 3-13 7-17z m171 94l-422 0 0 245 422 0z"/>
|
|
||||||
<glyph glyph-name="device-mobile" unicode="$" d="M294 89c0-9-7-17-17-17l-43 0c-9 0-16 8-16 17 0 10 7 17 16 17l43 0c10 0 17-7 17-17z m107 381l0-428c0-23-19-42-43-42l-204 0c-24 0-43 19-43 42l0 428c0 23 19 42 43 42l204 0c24 0 43-19 43-42z m-245-3l0-294 200 0 0 294z m200-422l0 94-200 0 0-94z"/>
|
|
||||||
<glyph glyph-name="device-tablet" unicode="%" d="M287 83c0-9-7-16-17-16l-28 0c-10 0-17 7-17 16 0 10 7 17 17 17l28 0c10 0 17-7 17-17z m175 387l0-428c0-23-19-42-42-42l-328 0c-23 0-42 19-42 42l0 428c0 23 19 42 42 42l328 0c23 0 42-19 42-42z m-367-3l0-306 322 0 0 306z m322-422l0 83-322 0 0-83z"/>
|
|
||||||
<glyph glyph-name="direction" unicode="&" d="M278 22c-1 0-3 0-4 1-10 1-17 9-18 19l-19 194-195 19c-10 2-18 9-19 19-2 10 4 19 13 24l423 190c8 3 18 2 25-5 6-7 8-17 4-25l-190-423c-4-8-12-13-20-13z m-148 269l128-13c11-1 19-9 20-20l14-128 131 293z"/>
|
|
||||||
<glyph glyph-name="disc" unicode="'" d="M256 512c-141 0-256-115-256-256 0-141 115-256 256-256 141 0 256 115 256 256 0 141-115 256-256 256z m0-45c117 0 211-94 211-211 0-29-6-58-17-84l-125 62c8 25 2 54-18 74-20 20-48 25-73 18l-45 91c-4 8-14 12-23 8-8-4-11-14-7-23l46-93c0 0 0 0-1-1 0 0 0 0 0 0l-127 62c38 59 104 97 179 97z m-24-187c7 7 15 10 24 10 9 0 17-3 24-10 13-13 13-35 0-48-13-13-35-13-48 0-13 13-13 35 0 48z m138-202l-29 59c-4 8-14 12-23 8-8-4-11-14-7-23l29-59c-26-11-55-18-84-18-117 0-211 94-211 211 0 29 6 58 17 84l125-62c-8-25-2-53 18-73 14-14 33-21 51-21 18 0 37 7 51 21 0 0 1 0 1 0l126-63c-16-25-38-47-64-64z m-50 103c3-3 6-8 6-14 0-5-3-10-6-14-3-4-9-6-14-6-5 0-10 3-14 6-4 3-5 9-5 14 0 5 2 10 5 14 7 7 21 7 28 0z"/>
|
|
||||||
<glyph glyph-name="document" unicode="(" d="M423 501l-334 0c-12 0-22-10-22-22l0-446c0-12 10-22 22-22l334 0c12 0 22 10 22 22l0 446c0 12-10 22-22 22z m-22-445l-290 0 0 400 290 0z m-237 147c0 11 9 20 20 20l65 0c11 0 20-9 20-20 0-10-9-19-20-19l-65 0c-11 0-20 9-20 19z m3 89c0 11 9 20 19 20l133 0c10 0 19-9 19-20 0-10-8-19-19-19l-133 0c-10 0-19 9-19 19z m0 84c0 10 9 19 19 19l133 0c10 0 19-9 19-19 0-11-8-20-19-20l-133 0c-10 0-19 9-19 20z m165-161c4-3 6-8 6-14 0-5-2-10-6-13-3-4-9-6-14-6-5 0-10 2-14 6-3 3-5 8-5 13 0 5 2 10 5 14 8 8 21 8 28 0z"/>
|
|
||||||
<glyph glyph-name="document-delete" unicode=")" d="M439 370l-123 124c-5 5-10 7-17 7l-210 0c-12 0-22-10-22-22l0-446c0-12 10-22 22-22l334 0c12 0 22 10 22 22l0 322c0 6-2 11-6 15z m-38-25l-112 0 0 111 2 0z m-290-289l0 400 134 0 0-133c0-12 9-22 22-22l134 0 0-245z m209 166l-37-37 37-36c8-8 8-20 0-28-4-4-9-5-14-5-5 0-10 1-14 5l-36 36-36-36c-4-4-9-6-14-6-5 0-10 2-14 6-8 8-8 20 0 27l37 37-37 36c-8 8-8 21 0 28 8 8 20 8 27 0l36-37 37 37c7 8 20 8 27 0 9-7 9-19 1-27z"/>
|
|
||||||
<glyph glyph-name="document-edit" unicode="*" d="M479 461l-39 40c-4 4-8 5-13 5-4 0-8-1-11-5l-233-236c-2-2-3-3-4-6l-27-66c-2-6-1-13 4-18 4-3 8-5 12-5 2 0 4 1 6 1l66 27c2 1 4 2 5 3l234 237c7 6 7 17 0 23z m-254-234l-27-11 11 28 218 222 17-17z m170 20l0-225c0-12-11-22-23-22l-316 0c-13 0-23 10-23 22l0 424c0 13 10 21 23 21l231 0c12 0 22-10 22-22 0-12-10-22-22-22l-209 0 0-378 273 0 0 202c0 12 10 22 22 22 12 0 22-10 22-22z"/>
|
|
||||||
<glyph glyph-name="document-new" unicode="+" d="M439 370l-123 124c-5 5-10 7-17 7l-210 0c-12 0-22-10-22-22l0-446c0-12 10-22 22-22l334 0c12 0 22 10 22 22l0 322c0 6-2 11-6 15z m-38-25l-112 0 0 111 2 0z m-290-289l0 400 134 0 0-133c0-12 9-22 22-22l134 0 0-245z"/>
|
|
||||||
<glyph glyph-name="document-remove" unicode="," d="M439 370l-123 124c-5 5-10 7-17 7l-210 0c-12 0-22-10-22-22l0-446c0-12 10-22 22-22l334 0c12 0 22 10 22 22l0 322c0 6-2 11-6 15z m-38-25l-112 0 0 111 2 0z m-290-289l0 400 134 0 0-133c0-12 9-22 22-22l134 0 0-245z m215 130c0-10-9-19-20-19l-100 0c-11 0-20 9-20 19 0 11 9 20 20 20l100 0c11 0 20-9 20-20z"/>
|
|
||||||
<glyph glyph-name="dot" unicode="-" d="M256 217c-10 0-21 4-28 12-7 7-11 17-11 27 0 10 4 20 11 28 7 7 17 11 28 11 10 0 20-4 27-11 8-7 12-17 12-28 0-10-4-20-12-27-7-8-17-12-27-12z"/>
|
|
||||||
<glyph glyph-name="dots-2" unicode="." d="M189 217c-10 0-20 4-28 12-7 7-11 17-11 27 0 10 5 20 11 28 8 7 18 11 28 11 10 0 20-4 27-11 8-7 12-17 12-28 0-10-4-20-12-27-7-8-17-12-27-12z m161 12c7 7 12 17 12 27 0 10-5 20-12 28-7 7-17 11-27 11-10 0-21-4-28-11-7-7-11-17-11-28 0-10 4-20 11-27 7-8 17-12 28-12 10 0 20 4 27 12z"/>
|
|
||||||
<glyph glyph-name="dots-3" unicode="/" d="M117 217c-10 0-21 4-28 12-7 7-11 17-11 27 0 10 4 20 11 28 7 7 17 11 28 11 10 0 20-4 27-11 7-7 12-17 12-28 0-10-5-20-12-27-7-8-17-12-27-12z m166 12c8 7 12 17 12 27 0 10-4 20-12 28-7 7-17 11-27 11-10 0-21-4-28-11-7-7-11-17-11-28 0-10 4-20 11-27 7-8 17-12 28-12 10 0 20 4 27 12z m139 0c8 7 12 17 12 27 0 10-4 20-12 28-7 7-17 11-27 11-10 0-20-4-28-11-7-7-11-17-11-28 0-10 5-20 11-27 8-8 18-12 28-12 10 0 20 4 27 12z"/>
|
|
||||||
<glyph glyph-name="download" unicode=":" d="M495 185l0-152c0-15-12-27-28-27l-422 0c-16 0-28 12-28 27l0 152c0 15 12 28 28 28 15 0 27-13 27-28l0-124 368 0 0 124c0 15 12 28 27 28 16 0 28-13 28-28z m-259-35c5-5 12-8 20-8 8 0 14 3 20 8l111 114c10 11 10 28-1 39-11 11-28 11-39 0l-63-65 0 241c0 15-12 27-28 27-16 0-28-12-28-27l0-241-63 64c-11 11-29 11-40 1-11-11-11-29 0-40z"/>
|
|
||||||
<glyph glyph-name="duplicate" unicode=";" d="M490 131l-336 0c-13 0-23 10-23 23l0 336c0 12 10 22 23 22l336 0c12 0 22-10 22-22l0-336c0-13-10-23-22-23z m-314 45l291 0 0 291-291 0z m194-149l0 59c0 9-8 16-17 16-9 0-17-7-17-16l0-53-302 0 0 303 52 0c9 0 16 7 16 16 0 9-7 17-16 17l-59 0c-15 0-27-12-27-27l0-316c0-14 12-26 27-26l316 0c15 0 27 12 27 27z"/>
|
|
||||||
<glyph glyph-name="enter" unicode="<" d="M495 440l0-368c0-12-10-22-22-22l-290 0c-12 0-22 10-22 22l0 102c0 12 10 22 23 22 12 0 22-10 22-22l0-79 245 0 0 322-245 0 0-79c0-12-10-22-22-22-13 0-23 10-23 22l0 102c0 12 10 22 22 22l290 0c12 0 22-10 22-22z m-236-256c-9-9-9-23 0-32 4-4 10-6 15-6 6 0 12 2 16 6l87 88c9 9 9 23 0 32l-86 89c-9 9-23 9-32 0-9-9-9-23 0-32l49-50-269-1c-12 0-22-10-22-22 0-12 10-22 22-22l269 0z"/>
|
|
||||||
<glyph glyph-name="exit" unicode="=" d="M334 174l0-102c0-12-9-22-21-22l-291 0c-12 0-22 10-22 22l0 368c0 12 10 22 22 22l291 0c12 0 21-10 21-22l0-102c0-12-10-22-22-22-13 0-23 10-23 22l0 79-244 0 0-322 244 0 0 79c0 12 10 22 23 22 12 0 22-10 22-22z m171 99l-86 88c-9 9-23 9-32 0-9-9-9-23 0-32l49-50-270-1c-12 0-22-10-22-22 0-12 10-22 22-22l270 0-49-50c-9-9-9-23 0-32 4-4 10-6 15-6 6 0 12 2 16 6l87 88c9 10 9 24 0 33z"/>
|
|
||||||
<glyph glyph-name="expand" unicode=">" d="M501 479l0-112c0-12-10-22-22-22-13 0-23 10-23 22l0 58-129-129c-4-5-10-7-15-7-6 0-11 2-16 7-9 8-9 22 0 31l129 129-58 0c-12 0-22 10-22 23 0 12 10 22 22 22l112 0c6 0 11-2 15-7 5-4 7-9 7-15z m-22-312c-13 0-23-10-23-22l0-58-127 126c-8 9-23 9-32 0-9-9-9-23 0-32l125-125-57 0c-12 0-22-10-22-23 0-12 10-22 22-22l111 0c7 0 13 2 17 7 5 4 8 10 8 15l0 112c0 12-10 22-22 22z m-296 47l-127-127 0 58c0 12-10 22-23 22-12 0-22-10-22-22l0-112c0-6 2-11 7-15 4-5 10-7 16-7l111 0c12 0 23 10 23 22 0 13-11 23-23 23l-58 0 127 127c9 8 9 22 0 31-8 9-23 9-31 0z m-96 240l58 0c12 0 22 10 22 22 0 13-10 23-22 23l-112 0c-6 0-11-3-15-7-5-4-7-9-7-16l0-111c0-12 10-22 22-22 13 0 23 10 23 22l0 58 128-129c5-4 10-6 16-6 5 0 11 2 15 6 9 9 9 23 0 32z"/>
|
|
||||||
<glyph glyph-name="expand-2" unicode="?" d="M501 479l0-117c0-13-10-23-22-23-13 0-23 10-23 23l0 63-140-141c-5-4-10-6-16-6-6 0-11 2-16 6-9 9-9 23 0 32l141 140-63 0c-13 0-23 10-23 23 0 12 10 22 23 22l117 0c6 0 11-2 15-7 5-4 7-9 7-15z m-307-254l-138-138 0 63c0 13-10 23-23 23-12 0-22-10-22-23l0-117c0-6 2-11 7-15 4-5 9-7 15-7l117 0c13 0 23 10 23 22 0 13-10 23-23 23l-63 0 139 138c9 9 9 23 0 32-9 8-23 8-32-1z"/>
|
|
||||||
<glyph glyph-name="experiment" unicode="@" d="M499 489c-4 7-12 12-20 12l-446 0c-8 0-16-5-20-12-4-7-2-16 3-23l173-255 0-168c0-17 12-32 30-32l74 0c18 0 30 14 30 32l0 168 173 255c5 7 7 16 3 23z m-216-259c-3-3-5-7-5-12l0-162-44 0 0 162c0 5-2 9-5 12l-53 78c11 3 24 6 39 6 17 0 29-3 42-7 13-3 26-6 45-7 11 0 21 1 30 2z m82 119c-1 0-24-10-63-10-14 0-24 3-36 7-13 3-29 7-51 7-25 0-47-6-63-11l-77 114 362 0z m-46 37c-4 4-7 10-7 16 0 6 2 11 7 15 4 4 10 7 15 7 7 0 12-2 16-7 4-4 7-10 7-15 0-6-2-12-7-16-4-4-10-6-16-6-5 0-11 2-15 6z"/>
|
|
||||||
<glyph glyph-name="export" unicode="[" d="M406 86l0-28c0-12-10-19-23-19l-363 0c-12 0-20 7-20 19l0 275c0 13 8 24 20 24l65 0c12 0 22-10 22-23 0-12-10-22-22-22l-40 0 0-229 317 0 0 3c0 13 10 23 22 23 12 0 22-10 22-23z m99 208l-138-141c-6-7-16-8-24-5-9 4-15 12-15 21l0 61c-44 1-151-3-190-72-4-7-12-12-19-12-2 0-4 0-6 1-10 3-17 12-17 22 0 3 0 89 65 153 40 42 95 64 167 68l0 61c0 9 6 17 14 20 9 4 19 2 25-5l139-140c8-9 8-23-1-32z m-48 16l-84 86 0-28c0-12-10-22-22-22-69 0-122-18-158-55-17-17-28-35-36-53 53 31 119 37 160 37 21 0 35-2 36-2 12-1 20-11 20-22l0-27z"/>
|
|
||||||
<glyph glyph-name="feed" unicode="]" d="M343 55c0-17-14-30-30-30-1 0-1 0-1 0-17 1-30 15-30 32 3 79-15 138-56 176-65 61-166 51-167 51-17-2-32 10-34 27-2 17 10 32 27 34 5 1 130 13 216-66 54-51 79-127 75-224z m-240 118c-19 0-38-8-51-21-14-13-21-32-21-51 0-19 7-38 21-51 13-14 32-22 51-22 19 0 38 8 51 22 14 13 21 32 21 51 0 19-7 38-21 51-13 13-32 21-51 21z m270 215c-127 119-313 98-321 97-17-2-29-17-27-34 2-16 17-29 34-26 2 0 166 18 273-81 67-62 98-159 93-287-1-16 12-31 29-31 1 0 1 0 1 0 16 0 30 12 31 29 7 146-31 258-113 333z"/>
|
|
||||||
<glyph glyph-name="flag" unicode="^" d="M483 511c-11 3-21-3-25-13-6-14-65-75-116-77-29-1-55 19-84 40-37 27-77 57-129 47-78-15-114-84-116-88-2-4-2-10-1-15l22-99 65-289c2-11 12-18 22-18 1 0 3 0 5 1 12 3 19 14 16 27l-37 168c10 16 38 54 83 64 26 6 47-1 72-9 27-8 58-19 98-10 84 19 141 120 143 250 0 10-7 19-18 21z m-135-228c-27-6-49 1-74 10-27 9-58 19-96 10-38-8-67-30-86-51l-2 10-33 144c9 15 35 49 79 58 34 6 62-15 95-39 32-24 68-50 112-49 38 2 76 24 106 48-13-67-46-128-101-141z"/>
|
|
||||||
<glyph glyph-name="flashlight" unicode="_" d="M238 256c0-9-7-17-17-17l-42 0c-9 0-16 8-16 17 0 9 7 17 16 17l42 0c10 0 17-8 17-17z m274 130l0-260c0-17-14-32-32-32l-53 0c-91 1-147 51-165 73l-230 0c-18 0-32 14-32 32l0 115c0 18 14 31 32 31l229 0c19 22 74 72 166 72l53 0c18 0 32-14 32-31z m-467-175l38 0 0 90-38 0z m350-70l0 230c-67-11-106-60-106-61-5-6-10-9-17-9l-155 0 0-90 155 0c7 0 12-3 16-9 2-2 40-50 107-61z m72 232l-38 0 0-234 38 0z"/>
|
|
||||||
<glyph glyph-name="folder" unicode="`" d="M445 384l-192 0-24 40c-4 6-11 10-19 10l-143 0c-12 0-22-10-22-22l0-312c0-12 10-22 22-22l378 0c12 0 22 10 22 22l0 261c0 12-10 23-22 23z m-22-262l-334 0 0 268 108 0 24-40c4-7 12-11 19-11l183 0z"/>
|
|
||||||
<glyph glyph-name="folder-open" unicode="{" d="M507 297c-4 6-11 9-17 9l-28 0 0 61c0 10-8 17-18 17l-195 0-25 41c-4 6-10 9-17 9l-144 0c-10 0-18-6-18-17l0-111-23 0c-6 0-13-3-17-8-4-5-6-13-4-19l41-189c2-10 11-18 21-18l381 0c10 0 18 8 21 17l46 189c2 7 0 14-4 19z m-424 98l113 0 25-41c3-6 10-9 17-9l185 0 0-39-340 0z m343-278l-345 0-31 145 411 0z"/>
|
|
||||||
<glyph glyph-name="forward" unicode="|" d="M72 95c-1 0-4 0-5 0-10 3-17 11-17 22 0 3 1 88 64 152 41 40 96 63 166 67l0 59c0 9 6 17 14 21 9 3 18 1 25-5l137-139c8-9 8-23 0-32l-137-139c-6-6-16-8-25-5-8 4-14 12-14 21l0 60c-44 1-150-3-188-71-4-7-12-11-20-11z m196 127c21 0 35-2 37-2 11-1 20-10 20-22l0-27 83 85-83 85 0-27c0-12-10-22-22-22-69 0-122-19-157-55-16-16-27-34-35-52 52 31 117 37 157 37z"/>
|
|
||||||
<glyph glyph-name="gaming" unicode="}" d="M338 340c5-4 8-11 8-18 0-6-3-13-8-18-4-4-11-7-17-7-7 0-14 3-18 7-5 5-7 12-7 18 0 7 2 13 7 18 4 4 11 7 18 7 6 0 13-3 17-7z m39-35c-6 0-12-3-17-7-5-5-8-11-8-18 0-7 3-13 8-18 4-4 11-7 17-7 7 0 14 3 18 7 5 5 7 11 7 18 0 7-2 13-7 18-4 4-11 7-18 7z m-189 12l-15 0 0 15c0 7-7 14-14 14-8 0-14-7-14-14l0-15-15 0c-8 0-14-6-14-14 0-7 6-14 14-14l15 0 0-14c0-8 6-14 14-14 7 0 14 6 14 14l0 14 15 0c8 0 14 7 14 14 0 8-6 14-14 14z m324-173c0-24-13-43-35-52-21-7-54-4-84 30-15 17-39 47-52 63-72-16-140-6-169 0-13-16-38-46-52-63-22-25-45-34-65-34-8 0-14 2-20 4-22 8-35 28-35 52 0 65 42 168 56 199-5 15-3 32 5 46 11 18 30 32 46 33 15 2 34-7 47-13 25 4 104 16 204 0 12 6 32 15 47 13 16-1 35-15 46-33 8-14 10-31 5-46 14-30 56-133 56-199z m-45 0c0 66-55 189-55 190-3 6-3 13 0 19 3 5 3 9 1 13-3 6-10 11-12 12-5 0-19-6-29-11-5-2-10-4-15-2-114 20-201 0-202 0-5-2-10-1-15 2-11 5-24 11-29 11-3-1-10-6-12-12-2-5-2-8 0-13 3-6 3-13 1-19 0-1-55-124-55-190 0-5 2-8 5-10 8-3 22 2 36 17 19 23 59 73 60 73 5 8 15 10 23 8 1 0 88-25 173 0 2 0 4 1 6 1 7 0 14-3 18-9 0 0 40-50 60-73 14-16 28-20 35-17 4 2 6 5 6 10z"/>
|
|
||||||
<glyph glyph-name="gear" unicode="~" d="M256 149c-59 0-107 47-107 107 0 59 47 107 107 107 59 0 107-47 107-107 0-59-48-107-107-107z m0 175c-37 0-68-31-68-68 0-37 31-68 68-68 37 0 68 31 68 68 0 37-31 68-68 68z m0-324l-3 0c-19 0-36 2-37 2-9 1-16 8-17 17l-6 40c-12 4-24 9-35 15l-31-24c-7-5-17-5-24 0-1 1-14 11-28 25l-2 2c-14 14-24 27-25 28-5 7-5 16 0 24l25 32c-6 11-11 23-15 35l-39 6c-8 1-15 8-16 17-1 1-3 18-3 37l0 3c0 19 2 36 2 37 1 9 8 16 17 17l40 6c4 12 9 24 15 35l-24 31c-5 7-5 17 0 24 1 1 11 14 25 28l2 2c14 14 27 24 28 25 7 5 16 5 24 0l32-25c11 6 23 11 35 15l6 39c1 8 8 15 17 16 1 1 18 3 37 3l3 0c19 0 36-2 37-2 9-1 16-8 17-17l6-40c12-4 24-9 35-15l31 24c7 5 17 5 24 0 1-1 14-11 28-25l2-2c14-14 24-27 25-28 5-7 5-16 0-24l-24-32c6-11 10-23 14-35l39-6c9-1 16-8 17-17 0-1 2-18 2-38l0-2c0-20-2-37-2-38-1-9-8-15-17-17l-40-5c-4-13-9-24-15-36l24-31c5-7 5-17 0-24-1-1-11-14-25-28l-2-2c-14-14-27-24-28-25-7-5-16-5-24 0l-32 25c-11-6-23-10-35-14l-6-39c-1-9-8-16-17-17-1 0-18-2-37-2z m-20 40c5 0 11 0 17 0l3 0c6 0 12 0 17 0l5 37c1 8 7 14 15 16 18 4 34 11 49 21 5 2 10 3 15 2 3-1 6-2 8-4l30-22c3 3 8 7 12 11l3 3c4 4 8 8 11 12l-22 30c-5 6-5 15-1 22 9 15 16 31 20 47 2 9 8 15 17 17l37 5c0 5 0 11 0 17l0 2c0 6 0 12 0 17l-37 5c-8 1-14 7-16 15-4 18-11 34-20 49-1 1-2 2-2 4-2 6-1 14 3 19l22 30c-3 3-7 8-11 12l-3 3c-4 4-8 8-12 11l-30-22c-7-5-17-5-23 0-15 9-31 16-47 20-8 2-14 8-16 17l-5 37c-5 1-11 1-17 1l-2 0c-6 0-12 0-17-1l-5-38c-1-9-8-15-17-16-17-4-33-11-47-20-5-3-10-3-15-2-3 0-6 2-8 4l-29 22c-4-3-8-7-13-12l-2-2c-4-4-8-9-12-13l23-29c5-7 5-15 1-23-1 0-1-1-1-1-9-15-16-31-20-47-2-8-8-14-17-16l-37-5c0-5 0-11 0-17l0-2c0-6 0-12 0-17l37-5c9-1 15-8 16-17 0 0 0-1 0-1 4-16 11-32 20-46 3-5 4-11 2-17-1-2-3-4-4-7l-22-29c3-3 7-8 12-12l2-3c4-4 9-8 13-11l29 22c7 6 18 5 25-1 14-8 30-15 46-19 8-2 14-8 15-17z"/>
|
|
||||||
<glyph glyph-name="graduation" unicode="\" d="M499 337l-234 105c-6 3-13 3-18 0l-234-105c-7-4-13-11-13-20 0-9 6-16 13-20l20-10 0-78c0-8 7-14 14-14 8 0 14 6 14 14l0 64 34-18 0-95c0-4 1-7 3-10 2-4 53-79 155-79 105 0 154 76 156 79 2 2 3 6 3 10l0 92 89 45c8 4 12 12 12 20-1 9-7 16-14 20z m-126-171c-11-13-49-56-120-56-69 0-108 42-119 56l0 69 112-57c3-2 7-2 10-2 3 0 7 0 11 2l106 54z m-117 57l-183 92 183 82 183-82z m-195-47c4-3 7-10 7-15 0-6-2-12-7-16-4-4-10-6-15-6-6 0-12 2-16 6-4 4-7 10-7 16 0 5 3 12 7 15 4 4 10 7 16 7 5 0 11-2 15-7z"/>
|
|
||||||
<glyph glyph-name="graph-bar" unicode="" d="M406 17c-18 0-33 15-33 33l0 412c0 18 15 33 33 33 19 0 34-15 34-33l0-412c0-18-15-33-34-33z m-117 33l0 276c0 18-15 34-33 34-18 0-33-16-33-34l0-276c0-18 15-33 33-33 18 0 33 15 33 33z m-150 0l0 140c0 19-15 34-33 34-19 0-34-15-34-34l0-140c0-18 15-33 34-33 18 0 33 15 33 33z"/>
|
|
||||||
<glyph glyph-name="graph-line" unicode="" d="M33 56c-5 0-10 1-14 4-13 7-17 25-10 38l68 113c5 8 14 14 23 14 10 0 19-4 24-12l29-40 61 105c5 7 14 13 23 14 9 0 18-4 23-12l54-71 141 233c7 14 25 18 38 10 13-8 17-25 10-39l-162-268c-5-8-14-13-23-14-9 0-18 4-24 11l-53 72-62-105c-5-8-13-13-23-14-9 0-18 4-24 12l-28 40-47-77c-5-9-14-14-24-14z"/>
|
|
||||||
<glyph glyph-name="graph-pie" unicode="" d="M187 305l-168 0c-10 0-19 9-19 19 0 104 84 188 187 188 11 0 19-9 19-19l0-168c1-11-8-20-19-20z m-146 39l127 0 0 127c-66-8-119-61-127-127z m232-344c-132 0-238 102-238 229 0 12 10 22 22 22l204 0 0 204c0 12 10 22 22 22 124 0 229-109 229-238 0-132-107-239-239-239z m-192 206c11-91 93-161 192-161 107 0 194 87 194 194 0 97-72 181-161 192l0-202c0-13-10-23-23-23z"/>
|
|
||||||
<glyph glyph-name="headset" unicode="" d="M495 274l0-141c0-12-10-22-23-22-12 0-22 10-22 22l1 141c0 52-20 100-57 137-37 36-85 56-137 56 0 0-1 0-1 0-107 0-194-86-195-192l0-141c0-13-10-23-22-23-12 0-22 10-22 23l0 141c0 131 108 237 239 237 0 0 1 0 1 0 64 0 124-25 168-70 46-45 70-105 70-168z m-291-12c4-4 5-8 5-13l0-225c0-11-9-18-20-18-73 0-97 42-100 65 0 1 0 0 0 1l0 127c0 1 0 1 0 2 3 23 27 66 100 66 0 0 1 0 1 0 5 0 10-1 14-5z m-34-34c-35-6-41-27-42-30l-1-125c2-4 8-24 43-30z m254-29l0-126c0-1 0-1 0-2-3-23-27-65-100-65-11 0-20 7-20 18l0 224c0 5 2 10 5 14 4 3 9 5 14 5 0 0 1 0 1 0 73 0 97-43 100-66 0-1 0-1 0-2z m-39-126l0 125c-2 4-8 24-43 30l1-185c35 7 41 27 42 30z"/>
|
|
||||||
<glyph glyph-name="heart" unicode="" d="M483 390c-23 50-71 83-122 83-52 0-86-23-105-47-19 24-53 47-105 47-51 0-99-33-122-83-23-53-13-112 28-157 97-110 183-187 185-188 4-4 9-5 15-5 5 0 10 1 15 5 1 1 86 79 184 188 40 45 50 104 27 157z m-61-128c-72-81-138-144-166-171-28 27-94 90-166 171-29 33-37 72-20 110 15 34 48 57 81 57 67 0 82-50 83-56 3-10 11-17 21-17 10 0 19 7 22 17 2 5 17 56 83 56 33 0 66-23 82-58 17-37 9-76-20-109z m-5 65c0-11-7-20-19-21 0 0-1 0-1 0-10 0-19 8-19 18-2 32-23 37-27 38-10 1-18 11-17 21 2 11 12 18 23 17 19-3 56-22 60-73z m-27-33c4-4 7-10 7-15 0-6-2-12-7-16-4-4-10-6-15-6-6 0-12 2-16 6-4 4-7 10-7 16 0 5 3 12 7 15 4 4 10 7 16 7 5 0 11-3 15-7z"/>
|
|
||||||
<glyph glyph-name="help" unicode="" d="M437 437c-49 48-113 75-181 75-68 0-132-27-181-75-48-49-75-113-75-181 0-68 27-132 75-181 49-48 113-75 181-75 68 0 132 27 181 75 48 49 75 113 75 181 0 68-27 132-75 181z m-50-150l76 12c3-14 4-29 4-43 0-14-1-29-4-43l-76 12c4 20 4 42 0 62z m67 45l-79-13c-7 12-14 23-24 32-9 10-20 18-32 24l13 79c27-11 53-27 74-48 21-22 37-47 48-74z m-198-166c-24 0-47 9-63 26-18 17-27 40-27 63 0 24 10 47 27 64 17 18 40 26 63 26 23 0 46-9 63-26 18-17 27-40 27-64 0-23-10-46-27-63-16-17-39-26-63-26z m0 301c14 0 29-1 43-4l-12-76c-20 5-42 5-62 0l-12 76c14 3 29 4 43 4z m-150-61c21 21 47 38 74 48l13-79c-12-7-23-14-32-24-10-9-17-20-24-32l-79 13c11 27 27 52 48 74z m-61-150c0 14 1 29 4 43l76-12c-2-10-4-20-4-31 0-11 1-21 4-31l-76-12c-3 14-4 29-4 43z m13-76l79 13c7-12 14-23 24-32 10-10 21-17 32-24l-12-79c-27 10-53 27-74 48-22 22-38 47-49 74z m198-135c-14 0-29 1-43 4l12 76c10-2 20-4 31-4 11 0 21 1 31 4l12-76c-14-3-29-4-43-4z m150 61c-21-21-47-38-74-48l-13 79c12 7 23 14 32 24 10 10 18 21 24 32l79-12c-11-28-27-53-48-75z"/>
|
|
||||||
<glyph glyph-name="home" unicode="" d="M490 239c-6 0-11 3-16 6l-218 214-218-214c-9-8-23-8-32 1-8 9-8 23 1 32l233 228c9 8 23 8 32 0l233-228c9-9 9-23 1-32-5-4-11-7-16-7z m-49-217l0 218c0 12-10 22-22 22-13 0-23-10-23-22l0-195-69 0 0 119c0 16-14 29-30 29l-82 0c-16 0-30-13-30-29l0-119-69 0 0 195c0 12-10 22-23 22-12 0-22-10-22-22l0-218c0-12 10-22 22-22l115 0c12 0 22 10 22 22l0 127 53 0 0-127c0-12 10-22 22-22l114 0c12 0 22 10 22 22z"/>
|
|
||||||
<glyph glyph-name="hourglass" unicode="" d="M434 56l-22 0 0 58c0 32-32 60-64 86-10 9-25 23-31 29l0 54c6 6 21 20 31 29 32 26 64 54 64 86l0 58 22 0c12 0 22 10 22 23 0 12-10 22-22 22l-356 0c-12 0-22-10-22-22 0-13 10-23 22-23l22 0 0-58c0-32 32-60 64-86 10-9 25-23 31-29l0-54c-6-6-21-20-31-29-32-26-64-54-64-86l0-58-22 0c-12 0-22-10-22-23 0-12 10-22 22-22l356 0c12 0 22 10 22 22 0 13-10 23-22 23z m-289 58c0 12 31 38 48 52 26 23 46 40 46 61l0 58c0 22-20 38-46 61-17 14-48 40-48 52l0 58 222 0 0-58c0-12-31-38-48-52-26-23-46-40-46-61l0-58c0-21 20-38 46-61 17-14 48-40 48-52l0-58-222 0z m161 292l0 11c0 11 9 20 20 20 10 0 19-8 19-20l0-11c0-10-9-19-19-19-11 0-20 9-20 19z"/>
|
|
||||||
<glyph glyph-name="inbox" unicode="" d="M512 294c0 0 0 2 0 2 0 1 0 1-1 2 0 1 0 2 0 3 0 0-1 1-1 2 0 0 0 1-1 1 0 1-1 2-1 3 0 0 0 0 0 0l-121 147c-4 5-10 8-17 8l-228 0c-7 0-13-3-17-8l-120-147c0 0-1 0-1 0 0-1-1-1-1-3 0 0 0-1-1-1 0-1 0-1 0-2 0-1-1-2-1-3 0 0 0-1 0-2 0 0 0-2 0-2 0-1 0-1 0-1l0-200c-1-23 19-43 44-43l422 0c25 0 45 20 45 44l0 199c0 0 0 1 0 1z m-360 123l207 0 83-100-73 0c-6 0-12-4-17-8l-50-59-92 0-50 59c-5 5-10 8-17 8l-74 0z m315-322l-422 0 0 178 88 0 48-56c6-7 14-11 23-11l104 0c9 0 16 5 23 11l48 56 88 0z"/>
|
|
||||||
<glyph glyph-name="information" unicode="" d="M241 101c-4 0-9 2-12 5-6 4-9 11-7 19l27 139-15-9c-9-5-21-2-26 8-5 9-3 21 7 26l52 30c6 4 15 3 21-1 6-5 9-12 8-20l-29-144 24 10c10 4 21 0 25-10 5-10 0-22-10-26l-57-25c-2-1-5-2-8-2z m55 266c5 5 8 13 8 20 0 7-2 14-8 19-5 5-12 9-19 9-8 0-15-3-20-9-5-5-8-12-8-19 0-7 3-15 8-20 5-5 12-8 20-8 7 0 14 3 19 8z m216-111c0 141-115 256-256 256-141 0-256-115-256-256 0-141 115-256 256-256 141 0 256 115 256 256z m-45 0c0-117-94-211-211-211-117 0-211 94-211 211 0 117 94 211 211 211 117 0 211-94 211-211z"/>
|
|
||||||
<glyph glyph-name="italic" unicode="" d="M282 342c5-5 6-13 5-20l-41-211c10 4 22 0 27-10 6-10 2-24-9-30l-14-8c-5-2-11-4-17-4-7 0-14 2-20 7-12 9-17 22-14 36l39 204-9 0c-13 0-23 10-23 22 0 13 10 23 23 23l36 0c7 0 13-4 17-9z m-10 95c-14 0-26-11-26-26 0-14 12-26 26-26 15 0 26 12 26 26 0 15-12 26-26 26z"/>
|
|
||||||
<glyph glyph-name="jewel" unicode="" d="M506 338l-94 100c-5 4-10 7-16 7l-280 0c-6 0-12-3-16-7l-94-100c-8-9-8-22 1-31l233-234c5-5 10-7 16-7 6 0 12 2 16 7l233 234c9 9 9 22 1 31z m-354-32l42-120-121 120z m123 95l36-56-110 0 36 56z m-19-280l0 1-62 184 124 0-62-184z m104 185l79 0-121-120z m81 39l-85 0-35 56 65 0z m-315 56l65 0-35-56-85 0z"/>
|
|
||||||
<glyph glyph-name="lifting" unicode="" d="M429 390l0-268c0-12-10-22-23-22-12 0-22 10-22 22l0 112-256 0 0-112c0-12-10-22-22-22-13 0-23 10-23 22l0 268c0 12 10 22 23 22 12 0 22-10 22-22l0-112 256 0 0 112c0 12 10 22 22 22 13 0 23-10 23-22z m-396-33c-12 0-22-10-22-23l0-157c0-12 10-22 22-22 13 0 23 10 23 22l0 157c0 13-10 23-23 23z m446 0c-13 0-23-10-23-23l0-157c0-12 10-22 23-22 12 0 22 10 22 22l0 157c0 13-10 23-22 23z"/>
|
|
||||||
<glyph glyph-name="lightbulb" unicode="" d="M256 512c-91 0-167-76-167-169 0-56 22-102 67-133l0-54c0-6 4-12 8-16 4-4 10-6 16-6 0 0 1 0 2 0l153 12c12 1 22 10 22 22l0 42c39 28 67 77 67 133-1 93-77 169-168 169z m67-270c-7-4-11-12-11-19l0-34-112-9 0 43c0 7-3 15-10 19-38 22-56 56-56 101 0 69 55 124 122 124 67 0 122-55 122-124 0-44-20-82-55-101z m31-143c1-13-8-23-21-24l-152-12c0 0-1 0-1 0-12 0-21 9-23 21-1 12 9 23 21 24l152 11c13 1 23-8 24-20z m-48-71c1-12-9-22-21-24l-55-4c0 0-1 0-1 0-12 0-21 9-23 21-1 12 9 22 21 24l55 4c12 1 23-8 24-21z m38 316c-1-10-9-18-19-18-1 0-1 0-2 0-10 1-18 11-17 21 3 32-24 44-28 45-10 4-15 15-11 25 3 10 14 15 24 12 21-8 58-35 53-85z"/>
|
|
||||||
<glyph glyph-name="link" unicode="" d="M505 156l-132 133c-9 9-23 9-32 0l-43-44-53 53 44 43c9 9 9 23 0 32l-133 132c-9 9-22 9-31 0l-118-118c-5-4-7-10-7-16 0-6 2-11 7-15l132-133c5-4 10-7 16-7 5 0 11 3 15 7l44 44 52-53-43-43c-9-9-9-23 0-32l132-132c5-5 10-7 16-7 6 0 11 2 15 7l119 118c9 9 9 23 0 31z m-350 114l-101 101 87 87 101-101-28-28-17 17c-9 9-23 9-32 0-9-9-9-23 0-32l17-16z m216-216l-101 101 28 28 17-17c4-5 10-7 16-7 5 0 11 2 15 7 9 9 9 23 0 32l-17 16 28 28 101-101z"/>
|
|
||||||
<glyph glyph-name="link-broken" unicode="" d="M207 245c0-12-10-22-22-22l-35-2c-5 0-10 2-14 6l-129 130c-5 5-7 10-7 16 0 7 2 12 7 16l116 116c9 9 23 9 32 0l130-130c9-9 9-23 0-31-9-9-23-8-32 0l-114 115-85-85 107-107 23 0c13 0 23-10 23-22z m298-90l-129 129c-4 5-9 6-14 6l-35-1c-12 0-22-10-22-22 0-12 10-22 22-22l24 0 108-107-86-85-114 115c-9 9-23 9-32 0-9-9-9-23 0-31l130-130c5-5 10-7 16-7 6 0 12 2 16 7l116 116c5 4 7 10 7 16 0 6-2 11-7 16z m-166 231c13 0 23 10 23 22l0 56c0 12-10 22-23 22-12 0-22-10-22-22l0-56c0-12 10-22 22-22z m66-69l55 0c12 0 23 10 23 22 0 13-11 23-23 23l-55 0c-13 0-23-10-23-23 0-12 10-22 23-22z m-232-187c-13 0-23-10-23-23l0-55c0-12 10-23 23-23 12 0 22 11 22 23l0 55c0 13-10 23-22 23z m-69 65l-56 0c-12 0-22-10-22-22 0-13 10-23 22-23l56 0c12 0 22 10 22 23 0 12-10 22-22 22z"/>
|
|
||||||
<glyph glyph-name="list" unicode="" d="M508 429c0-19-15-34-34-34l-306 0c-19 0-34 15-34 34 0 18 15 33 34 33l306 0c19 0 34-15 34-33z m-340-206l174 0c18 0 33 15 33 33 0 18-15 33-33 33l-174 0c-19 0-34-15-34-33 0-18 15-33 34-33z m245-106l-245 0c-19 0-34-15-34-34 0-18 15-33 34-33l245 0c19 0 34 15 34 33 0 19-15 34-34 34z m-375 348c-10 0-19-4-26-11-6-7-11-16-11-25 0-10 4-19 11-26 6-7 16-11 25-11 10 0 19 4 26 11 7 7 10 16 10 26 0 9-3 18-10 25-6 7-16 11-25 11z m0-173c-10 0-19-4-26-10-6-7-11-17-11-26 0-9 4-19 11-26 6-6 16-10 25-10 10 0 19 4 26 10 7 7 10 17 10 26 0 9-3 19-10 26-6 6-16 10-25 10z m0-172c-10 0-19-4-26-11-6-7-11-16-11-26 0-9 4-18 11-25 6-7 16-11 25-11 10 0 19 4 26 11 7 7 10 16 10 25 0 10-3 19-10 26-6 7-16 11-25 11z"/>
|
|
||||||
<glyph glyph-name="loading" unicode="" d="M256 369c-12 0-22 10-22 22l0 96c0 12 10 22 22 22 12 0 22-10 22-22l0-96c0-12-10-22-22-22z m-66-22c10 8 12 21 5 31l-57 78c-7 10-21 12-31 5-10-7-12-21-5-31l56-78c5-6 11-9 18-9 5 0 10 1 14 4z m-41-56c3 12-3 25-15 28l-91 29c-12 4-25-2-28-14-4-11 3-24 14-28l92-29c2-1 4-2 6-2 10 0 18 7 22 16z m-106-127l91 29c12 4 18 16 15 28-4 12-17 18-28 14l-92-29c-11-4-18-16-14-28 3-9 12-15 21-15 2 0 5 0 7 1z m95-108l57 78c7 10 5 23-5 31-10 7-24 5-31-5l-57-78c-7-10-5-24 5-31 4-3 9-4 13-4 7 0 14 3 18 9z m140-31l0 96c0 12-10 22-22 22-12 0-22-10-22-22l0-96c0-12 10-22 22-22 12 0 22 10 22 22z m127 26c10 7 12 21 5 31l-57 78c-7 10-21 12-31 5-10-8-12-21-5-31l56-78c5-6 12-9 18-9 5 0 10 1 14 4z m92 127c4 11-3 24-14 27l-92 30c-11 4-24-3-28-15-3-11 3-24 15-27l91-30c2 0 5-1 7-1 9 1 18 7 21 16z m-106 99l92 29c11 4 18 16 14 28-4 12-16 18-28 14l-91-29c-12-4-18-16-15-28 3-9 12-16 22-16 2 0 4 1 6 2z m-38 75l57 78c7 10 5 24-5 31-10 7-24 5-32-5l-56-78c-7-10-5-23 5-31 4-3 9-4 13-4 7 0 14 3 18 9z"/>
|
|
||||||
<glyph glyph-name="location" unicode="" d="M381 468c-32 28-77 44-125 44-48 0-93-16-125-44-39-34-59-86-59-151 0-139 161-304 168-310 5-5 10-7 16-7 6 0 12 2 16 7 7 6 168 171 168 310 0 65-20 117-59 151z m-125-413c-15 17-39 45-62 78-50 71-77 135-77 184 0 139 106 150 139 150 129 0 139-115 139-150 0-98-99-218-139-262z m0 361c-49 0-88-41-88-90 0-50 39-90 88-90 49 0 88 41 88 90 0 50-39 90-88 90z m0-141c-27 0-50 23-50 51 0 29 23 51 50 51 27 0 50-22 50-51 0-28-23-51-50-51z"/>
|
|
||||||
<glyph glyph-name="lock" unicode="" d="M406 328l-16 0 0 39c0 82-56 139-134 139-78 0-134-57-134-139l0-39-16 0c-13 0-23-10-23-22l0-278c0-12 10-22 23-22l300 0c13 0 23 10 23 22l0 278c0 12-10 22-23 22z m-239 39c0 57 37 95 89 95 52 0 89-38 89-95l0-39-178 0z m217-317l-256 0 0 234 256 0z"/>
|
|
||||||
<glyph glyph-name="lock-open" unicode="" d="M406 328l-239 0 0 39c0 57 36 95 88 95 38 0 68-20 81-54 4-12 17-17 29-13 11 5 17 17 12 29-19 51-65 82-122 82-77 0-133-57-133-139l0-39-16 0c-13 0-23-10-23-22l0-278c0-12 10-22 23-22l300 0c13 0 23 10 23 22l0 278c0 12-10 22-23 22z m-22-278l-256 0 0 234 256 0z"/>
|
|
||||||
<glyph glyph-name="mail" unicode="" d="M512 385c0 0 0 1 0 2 0 0 0 1 0 1 0 1-1 2-1 3 0 0 0 1 0 2 0 0-1 1-1 2-1 0-1 1-1 2 0 0 0 0 0 0-1 1-1 1-1 1-1 1-2 2-2 2-1 1-1 1-2 1 0 1-1 1-1 1-1 1-2 1-2 1-1 1-1 1-2 2 0 0-1 0-2 0-1 0-1 1-2 1-1 0-2 0-2 0-1 0-2 0-2 0l-469 0c0 0-1 0-1 0-1 0-2 0-3 0 0 0-1-1-2-1 0 0-2 0-2 0-1 0-1-1-2-2 0 0-1 0-1-1-1 0-2 0-2-1-1 0-1-1-2-1 0 0-1-1-1-2-1 0-1 0-2-1 0 0 0 0 0 0 0-1-1-2-1-2 0-1 0-2-1-2 0-1 0-1 0-2 0-1-1-1-1-3 0 0 0-1 0-1 0-1 0-2 0-2 0 0 0-1 0-1l0-256c0-12 10-22 22-22l468 0c12 0 22 10 22 22l-1 257c0-1 0 0 0 0z m-90-23l-166-124-166 124z m-377-212l0 189 198-146c4-3 8-5 13-5 5 0 9 2 13 5l198 146 0-189z"/>
|
|
||||||
<glyph glyph-name="map" unicode="" d="M502 430l-117 55c-1 0-1 0-1 0-1 1-2 1-2 1-1 0-2 0-2 0-1 0-2 0-3 0 0 0-1 0-2 0 0 0-2 0-2 0-1 0-2-1-2-1-1 0-1 0-1 0l-110-51-111 51c0 0 0 0-1 0-1 1-2 1-2 1-1 0-2 0-2 0-1 0-2 0-3 0 0 0-1 0-2 0 0 0-2 0-2 0-1 0-2-1-2-1-1 0-1 0-1 0l-121-55c-7-4-13-10-13-18l0-362c0-7 5-13 11-17 3-2 7-3 11-3 2 0 6 1 9 2l109 51 110-51c2 0 3-1 4-1 0 0 0 0 1 0 1 0 2 0 4 0 1 0 3 0 4 0 0 0 0 0 1 0 1 1 2 1 3 1l110 51 109-51c3-1 6-1 9-1 4 0 6 1 9 3 5 4 7 10 7 17l0 361c1 8-2 14-9 18z m-268-349l-73 36 0 319 73-37z m-195 318l78 37 0-319-78-36z m239 0l78 37 0-319-78-36z m195-318l-78 36 0 319 78-37z"/>
|
|
||||||
<glyph glyph-name="media-loop" unicode="" d="M440 332l0-221c0-12-10-22-23-22l-322 0c-13 0-23 10-23 22l0 221c0 12 10 24 23 24l123 0-30 30c-9 9-8 22 0 30 9 9 23 9 32 0l68-68c8-9 8-23 0-31l-68-69c-5-4-10-6-16-6-5 0-11 2-15 6-9 9-9 24 0 32l30 31-102 0 0-178 278 0 0 179-47 0c-12 0-22 10-22 22 0 12 10 22 22 22l69 0c13 0 23-12 23-24z"/>
|
|
||||||
<glyph glyph-name="media-next" unicode="" d="M331 273l-234 184c-6 5-15 6-23 3-8-4-13-12-13-20l0-368c0-8 5-16 13-20 3-1 7-2 9-2 5 0 10 2 14 5l234 184c6 4 8 10 8 17 0 7-3 13-8 17z m-225-155l0 276 175-138z m345 313l0-354c0-14-11-25-25-25-14 0-25 11-25 25l0 354c0 14 11 25 25 25 14 0 25-11 25-25z"/>
|
|
||||||
<glyph glyph-name="media-pause" unicode="" d="M184 440l0-368c0-15-13-27-28-27-16 0-28 12-28 27l0 368c0 15 12 27 28 27 15 0 28-12 28-27z m172 27c-15 0-28-12-28-27l0-368c0-15 13-27 28-27 16 0 28 12 28 27l0 368c0 15-12 27-28 27z"/>
|
|
||||||
<glyph glyph-name="media-play" unicode="" d="M387 273l-234 184c-7 5-16 6-23 3-8-4-13-12-13-20l0-368c0-8 5-16 13-20 3-1 6-2 9-2 5 0 10 2 14 5l234 184c5 4 8 10 8 17 0 7-3 13-8 17z m-226-155l0 276 176-138z"/>
|
|
||||||
<glyph glyph-name="media-previous" unicode="" d="M438 460c-8 4-17 2-23-3l-231-184c-6-4-9-10-9-17 0-7 4-13 9-17l231-184c4-3 9-5 14-5 3 0 6 1 9 2 8 4 13 12 13 20l0 368c0 8-5 16-13 20z m-32-341l-173 137 173 137z m-300 312l0-354c0-14-11-25-25-25-14 0-25 11-25 25l0 354c0 14 11 25 25 25 14 0 25-11 25-25z"/>
|
|
||||||
<glyph glyph-name="media-record" unicode="" d="M256 42c-118 0-214 96-214 214 0 118 96 214 214 214 118 0 214-96 214-214 0-118-96-214-214-214z m0 378c-91 0-164-73-164-164 0-91 73-164 164-164 91 0 164 73 164 164 0 91-73 164-164 164z"/>
|
|
||||||
<glyph glyph-name="media-shuffle" unicode="" d="M380 345c-24 0-82-58-125-100-65-62-126-123-175-123l-30 0c-12 0-22 10-22 23 0 12 10 22 22 22l30 0c31 0 94 62 144 111 61 59 114 112 156 112l28 0-30 29c-9 9-9 22 0 31 9 9 23 9 32 0l68-69c5-4 7-10 7-15 0-6-2-12-7-16l-69-68c-4-5-10-7-16-7-5 0-11 3-15 7-9 9-9 24 0 32l30 31z m29-115c-9 9-23 9-32 0-9-9-9-23 0-32l31-31-29 0c-18 0-49 27-79 55-9 8-23 8-32-1-8-8-8-23 1-32 47-43 78-67 111-67l28 0-30-29c-9-9-9-22 0-31 4-5 10-6 15-6 6 0 12 2 16 6l68 69c5 4 7 10 7 15 0 6-2 12-7 16z m-359 115l30 0c24 0 59-30 86-55 5-4 10-6 15-6 7 0 13 2 17 7 8 9 8 24-2 32-43 40-80 67-116 67l-30 0c-12 0-22-10-22-22 0-12 10-23 22-23z"/>
|
|
||||||
<glyph glyph-name="media-stop" unicode="" d="M467 442c0 14-11 25-25 25l-378 0c-14 0-25-11-25-25l0-378c0-14 11-25 25-25l378 0c14 0 25 11 25 25z m-50-353l-328 0 0 328 328 0z"/>
|
|
||||||
<glyph glyph-name="medical" unicode="" d="M505 385c-4 3-9 5-15 5l-117 0 0 66c0 13-11 23-24 23l-186 0c-13 0-24-10-24-23l0-66-117 0c-12 0-22-8-22-20l0-314c0-13 10-23 22-23l468 0c12 0 22 10 22 23l0 313c0 6-2 11-7 16z m-321 49l144 0 0-44-144 0z m283-356l-422 0 0 267 422 0z m-302 136c0 11 9 20 20 20l49 0 0 49c0 11 9 20 19 20 11 0 20-9 20-20l0-49 54 0c11 0 20-9 20-20 0-10-9-19-20-19l-54 0 0-53c0-10-9-19-20-19-10 0-19 8-19 19l0 53-49 0c-11 0-20 9-20 19z"/>
|
|
||||||
<glyph glyph-name="menu" unicode="" d="M434 381l-356 0c-20 0-36 16-36 36 0 20 16 37 36 37l356 0c20 0 36-17 36-37 0-20-16-36-36-36z m36-125c0 20-16 36-36 36l-356 0c-20 0-36-16-36-36 0-20 16-36 36-36l356 0c20 0 36 16 36 36z m0-161c0 20-16 36-36 36l-356 0c-20 0-36-16-36-36 0-20 16-37 36-37l356 0c20 0 36 17 36 37z"/>
|
|
||||||
<glyph glyph-name="message" unicode="" d="M490 479l-468 0c-12 0-22-10-22-23l0-284c0-12 10-22 22-22l262 0 0-94c0-10 7-18 15-21 3-2 6-2 9-2 6 0 13 3 17 8l92 109 73 0c12 0 22 10 22 22l0 284c0 13-10 23-22 23z m-23-284l-60 0c-6 0-14-4-18-8l-61-71 0 56c0 12-7 23-20 23l-263 0 0 239 422 0z m-363 161c0 12 10 22 22 22l161 0c12 0 22-10 22-22 0-12-10-22-22-22l-161 0c-12 0-22 10-22 22z m244-17c-4 4-7 10-7 16 0 6 2 11 7 15 4 5 10 7 15 7 7 0 12-2 16-7 4-4 7-10 7-15 0-7-3-12-7-16-4-5-10-7-16-7-5 1-11 3-15 7z"/>
|
|
||||||
<glyph glyph-name="meter" unicode="" d="M405 373l-108-232c-9-24-26-38-44-38-15 0-28 8-35 20-8 14-8 32 2 47l141 227c7 11 22 15 34 9 11-6 16-20 10-33z m38-67c-8 9-22 10-32 1-9-8-9-22-1-32 37-40 57-92 57-147 0-12 10-22 23-22 12 0 22 10 22 22 0 66-24 130-69 178z m-169 37c12-1 23 8 24 20 1 12-8 23-20 24-8 0-15 1-22 1-141 0-256-117-256-261 0-12 10-22 22-22 13 0 23 10 23 22 0 120 94 216 211 216 6 1 12 0 18 0z"/>
|
|
||||||
<glyph glyph-name="microphone" unicode="" d="M380 22c0-12-10-22-23-22l-203 0c-13 0-23 10-23 22 0 13 10 23 23 23l82 0 0 37c0 11 9 20 20 20 11 0 20-9 20-20l0-37 82 0c12 0 22-10 22-23z m-5 329c-11 0-20-9-20-20l0-145c0-8-3-16-9-21-5-6-13-9-20-9l-140 0c-7 0-15 3-20 9-6 6-9 13-9 21l0 145c0 11-9 20-20 20-11 0-20-9-20-20l0-145c0-18 7-36 20-49 13-13 31-20 49-20l140 0c18 0 36 7 49 20 13 14 20 31 20 49l0 145c0 11-9 20-20 20z m-179-152c-8 9-12 20-12 31l0 232c0 12 4 23 12 33 9 11 21 17 33 17l54 0c25 0 45-27 45-49l0-231c0-23-20-48-45-48l-54-1c-12 0-24 5-33 16z m33 31c0-1 1-3 3-4l48 0c1 1 3 3 3 5l0 232c0 1-2 3-3 4l-48 0c-2-1-3-3-3-5z"/>
|
|
||||||
<glyph glyph-name="minus" unicode="" d="M378 231l-244 0c-14 0-25 11-25 25 0 14 11 25 25 25l244 0c14 0 25-11 25-25 0-14-11-25-25-25z"/>
|
|
||||||
<glyph glyph-name="monitor" unicode="" d="M512 440c0 12-10 22-22 22l-468 0c-12 0-22-10-22-22l0-290c0-12 10-22 22-22l468 0c12 0 22 10 22 22z m-45-267l-422 0 0 244 422 0z m-80-101c0-12-10-22-22-22l-218 0c-12 0-22 10-22 22 0 13 10 23 22 23l217 0c13 0 23-10 23-23z"/>
|
|
||||||
<glyph glyph-name="move" unicode="" d="M512 254c0-6-2-11-7-15l-78-78c-5-5-10-6-16-6-5 0-11 2-15 6-9 9-9 24 0 32l40 41-158 0 0-158 41 41c9 9 23 8 32 0 9-9 8-23 0-32l-79-78c-4-5-10-7-16-7-6 0-11 2-16 7l-78 78c-9 8-9 22 0 31 9 9 23 9 31 0l41-40 0 158-158 0 41-41c9-9 9-24 0-33-5-4-10-6-16-6-5 0-11 2-15 6l-79 79c-5 4-7 9-7 15 0 6 2 12 7 16l78 78c9 9 23 9 32 0 9-9 8-22 0-31l-41-39 158 0 0 158-41-40c-9-9-23-9-31 0-9 9-8 23 0 31l78 78c9 9 23 9 32 0l79-78c9-8 9-22 0-31-5-5-10-7-16-7-6 0-12 2-16 7l-41 40 0-158 158 0-41 40c-9 9-9 21 0 30 9 9 23 9 32 0l78-78c5-4 7-10 7-16z"/>
|
|
||||||
<glyph glyph-name="music" unicode="" d="M495 477c0 7-3 13-9 17-5 5-11 6-18 5l-280-57c-11-2-18-11-18-22l0-255c-16 9-35 14-55 14-25 0-49-8-68-24-20-16-30-36-30-60 0-48 44-84 98-84 26 0 49 7 67 22 19 16 29 37 29 60l0 0 2 218 236 48 0-132c-15 8-33 12-53 12-25 0-49-7-68-22-20-16-31-37-31-61 0-47 45-84 99-84 51 0 94 34 98 79 0 0 0 3 0 9z m-340-410c-10-9-24-11-40-11-29 0-54 16-54 39 0 10 5 19 15 26 10 9 24 12 40 12 29 0 54-18 54-40 0-10-5-18-15-26z m59 284l0 51 236 48 0-50z m182-234c-29 0-54 18-54 40 0 10 5 18 14 26 11 9 25 12 40 12 28 0 55-15 55-36l0-6c-6-21-27-36-55-36z"/>
|
|
||||||
<glyph glyph-name="network-1" unicode="" d="M364 125c-25 0-46-19-55-36l-121 0c-10 0-15 5-15 15l0 124 136 0c9-22 30-36 55-36 33 0 60 27 60 59 0 32-27 59-60 59-25 0-46-15-55-37l-136 0 0 119c0 0-2 1-2 1 22 9 37 30 37 54 0 33-27 59-59 59-33 1-60-26-60-58 0-24 16-46 38-55 0 0 1 0 1 0l0-289c0-34 26-59 60-59l121 0c9-23 30-39 55-39 33 0 60 27 60 59 0 32-28 60-60 60z m0 152c14 0 26-12 26-26 0-14-12-26-26-26-15 0-26 12-26 26 0 14 11 26 26 26z m-216 197c15 0 26-12 26-26 0-14-11-26-26-26-14 0-26 12-26 26 0 14 12 26 26 26z m216-436c-15 0-26 12-26 26 0 14 11 26 26 26 14 0 26-12 26-26 0-14-12-26-26-26z"/>
|
|
||||||
<glyph glyph-name="network-2" unicode="" d="M429 447c0 33-27 59-59 59-33 0-60-26-60-59 0-24 15-45 37-54-1-10-7-72-94-104-40-15-69-34-86-54l0 158c22 9 36 30 36 54 0 33-28 59-60 59-33 0-58-26-58-59 0-24 15-45 37-54l0-274c-22-9-38-30-38-54 0-33 26-59 58-59 33 0 61 26 61 59 0 24-14 45-37 54l0 18c0 6 3 74 102 110 118 43 124 135 124 146 22 9 37 30 37 54z m-287 26c15 0 26-12 26-26 0-13-12-25-26-25-14 0-25 12-25 25 0 14 11 26 25 26z m0-434c-14 0-25 12-25 26 0 13 12 25 25 25 15 0 26-12 26-25 0-14-12-26-26-26z m228 383c-15 0-26 12-26 25 0 14 12 26 26 26 14 0 25-12 25-26 0-13-11-25-25-25z"/>
|
|
||||||
<glyph glyph-name="network-3" unicode="" d="M462 119l0 120c0 34-24 62-58 62l-126 0 0 91c0 0 0 1 0 1 22 9 37 30 37 54 0 33-26 59-59 59-33 0-59-26-59-59 0-24 16-45 37-54 0 0 0-1 0-1l0-91-126 0c-34 0-58-28-58-62l0-120c-22-9-38-30-38-54 0-33 25-59 58-59 32 0 60 26 60 59 0 24-19 45-36 54l0 120c0 10 5 17 13 17l127 0 0-137c-23-9-37-30-37-54 0-33 26-59 59-59 33 0 59 26 59 59 0 24-14 45-37 54l0 137 126 0c9 0 13-8 13-17l0-120c-16-9-35-30-35-54 0-33 28-59 60-59 33 0 58 26 58 59 0 24-16 45-38 54z m-206 354c14 0 26-12 26-26 0-13-12-25-26-25-14 0-26 12-26 25 0 14 12 26 26 26z m-187-434c-14 0-26 12-26 26 0 13 12 25 26 25 14 0 26-12 26-25 0-14-12-26-26-26z m187 0c-14 0-26 12-26 26 0 13 12 25 26 25 14 0 26-12 26-25 0-14-12-26-26-26z m187 0c-14 0-26 12-26 26 0 13 12 25 26 25 14 0 26-12 26-25 0-14-12-26-26-26z"/>
|
|
||||||
<glyph glyph-name="network-4" unicode="" d="M215 450c0 33-26 59-59 59-32 0-61-26-61-59 0-25 16-47 33-55l0-278c-17-8-33-30-33-55 0-33 28-59 60-59 33 0 59 26 59 59 0 25-14 47-36 55l0 278c22 8 37 30 37 55z m-58 25c14 0 26-11 26-25 0-14-12-26-26-26-13 0-25 12-25 26 0 14 11 25 25 25z m0-438c-13 0-25 11-25 25 0 14 12 26 25 26 14 0 26-12 26-26 0-14-12-25-26-25z m227 80l0 278c17 8 33 30 33 55 0 33-28 59-61 59-33 0-59-26-59-59 0-25 15-47 37-55l0-278c-22-8-37-30-37-55 0-33 26-59 59-59 32 0 61 26 61 59 0 25-16 47-33 55z m-29 358c13 0 25-11 25-25 0-14-12-26-25-26-14 0-26 12-26 26 0 14 12 25 26 25z m0-438c-14 0-26 11-26 25 0 14 12 26 26 26 13 0 25-12 25-26 0-14-11-25-25-25z"/>
|
|
||||||
<glyph glyph-name="network-5" unicode="" d="M278 119l0 273c0 0 0 1 0 1 21 9 36 30 36 54 0 33-26 59-58 59-32 0-58-26-58-59 0-24 15-45 36-54 0 0 0-1 0-1l0-273c-21-9-36-30-36-54 0-33 26-59 58-59 32 0 58 26 58 59 0 24-15 45-36 54z m-22 354c14 0 25-12 25-26 0-13-11-25-25-25-14 0-25 12-25 25 0 14 11 26 25 26z m0-434c-14 0-25 12-25 26 0 13 11 25 25 25 14 0 25-12 25-25 0-14-11-26-25-26z"/>
|
|
||||||
<glyph glyph-name="pamphlet" unicode="" d="M454 495c-5 4-12 4-18 1l-117-55-118 55c-1 0-1 0-1 1-1 1-2 1-2 1-1 0-2 0-3 0 0 0-1 0-2 0 0 0-2 0-2 0-1 0-2 0-2 0-1 0-2-1-3-1 0 0 0 0-1-1l-128-59c-7-3-12-10-12-17l0-387c0-6 5-12 10-16 3-3 7-3 11-3 3 0 6 0 9 2l118 55 118-55c1-1 2-2 3-2 0 0 0 0 1 0 1 0 2 0 4 0 2 0 2 0 4 0 0 0 0 0 1 0 1 1 2 1 3 2l125 59c7 3 10 10 10 17l0 387c0 6-2 12-8 16z m-153-431l-90 41 0 343 90-41z m-218 343l90 41 0-343-90-41z m340-302l-84-41 0 343 84 41z"/>
|
|
||||||
<glyph glyph-name="paperclip" unicode="" d="M473 308c8-7 8-20 0-28l-221-220c-37-38-79-57-119-57-10 0-20 1-30 4-39 10-69 40-80 81-13 50 5 105 50 150l247 246c40 40 96 27 128-5 44-44 32-96 2-125l-249-248c-32-33-70-31-89-11-19 19-21 55 12 89l168 168c8 8 20 8 28 0 8-8 8-20 0-28l-169-168c-15-15-17-29-12-34 6-6 20-3 34 11l249 249c25 25 14 53-2 70-19 19-50 28-73 4l-246-246c-35-35-50-76-40-112 7-27 27-47 53-53 34-10 74 6 110 42l222 222c7 7 19 7 27-1z"/>
|
|
||||||
<glyph glyph-name="pencil" unicode="" d="M496 478l-18 18c-11 10-24 16-39 16-15 0-28-6-39-16l-352-352c-2-3-3-5-5-8l-41-105c-4-9-2-18 5-24 4-5 10-7 15-7 3 0 6 1 9 2l105 41c3 1 6 3 8 5l352 352c22 21 22 56 0 78z m-414-365l32-31-52-20z m382 318l-307-307-32 32 306 308c3 3 6 3 8 3 2 0 5 0 8-3l18-18c4-4 4-10-1-15z"/>
|
|
||||||
<glyph glyph-name="phone" unicode="" d="M493 442c-1 1-1 1-2 2l-60 52c-8 8-19 12-31 10-11-1-22-5-29-13-1 0-1-1-2-2l-59-74c-16-17-15-42 1-59 1-1 2-2 3-2l30-20c-2-11-17-41-72-96-55-55-86-70-96-72l-20 30c0 1-1 2-2 3-17 16-43 16-59 1l-74-59c0-1-1-1-2-2-16-16-17-44-2-60l52-60c1 0 1 0 1-1 10-10 26-14 43-14 31 0 66 12 84 20 36 14 105 47 174 116 51 52 93 113 117 175 10 27 33 96 5 125z m-154-269c-103-103-219-131-238-122l-51 59 72 57 20-30c0 0 0-1 1-1 7-9 16-13 27-14 11 0 44-2 132 87 22 21 89 88 86 132 0 11-5 20-13 27 0 0-1 1-2 1l-28 20 57 73 58-51c10-19-18-135-121-238z"/>
|
|
||||||
<glyph glyph-name="photo" unicode="" d="M490 451l-468 0c-12 0-22-10-22-22l0-346c0-12 10-22 22-22l468 0c12 0 22 10 22 22l0 346c0 12-10 22-22 22z m-23-45l0-186-37 31c-8 7-20 7-28 0l-60-50-140 121c-8 7-20 7-28 1l-129-104 0 187z m-422-300l0 55 142 116 140-122c8-7 20-7 29 0l60 50 51-44 0-55z m245 225c0 22 18 40 41 40 23 0 41-18 41-40 0-23-18-41-41-41-23 0-41 18-41 41z"/>
|
|
||||||
<glyph glyph-name="photo-group" unicode="" d="M510 371l-53-255c-1-8-8-14-16-14-1 0-2 0-3 1-9 2-15 11-13 19l50 239-320 65-8-36c-2-9-11-14-20-13-8 3-14 11-12 20l11 52c3 9 11 15 20 13l352-71c4-1 8-4 10-8 2-3 3-8 2-12z m-104-304c0-12-10-22-22-22l-362 0c-12 0-22 10-22 22l0 272c0 13 10 23 22 23l362 0c12 0 22-10 22-23z m-361 250l0-137 94 76c7 6 18 6 26-1l105-93 44 38c8 6 16 6 23 0l19-19 0 136z m311-228l0 41-31 29-42-38c-8-6-18-6-25 0l-108 94-105-86 0-40z m-92 138c19 0 34 15 34 33 0 19-16 34-34 34-19 0-34-15-34-34-1-18 15-33 34-33z"/>
|
|
||||||
<glyph glyph-name="pill" unicode="" d="M462 462c-24 26-57 39-92 39-35 0-67-13-92-39l-228-228c-26-25-39-58-39-92 0-35 13-68 39-92 24-25 57-39 92-39 35 0 68 13 92 39l229 228c25 25 38 58 38 93 0 35-13 67-39 91z m-259-381c-17-16-38-25-61-25-23 0-45 9-61 25-16 16-25 38-25 60 0 23 9 45 25 61l93 93c26-17 89-62 122-121z m228 228l-107-106c-35 57-92 100-122 121l107 107c17 16 38 25 61 25 23 0 45-9 61-25 16-16 25-38 25-60 0-23-9-45-25-62z m-111 66c8-8 8-20 0-28l-27-27c-4-4-9-6-14-6-5 0-10 2-14 6-7 8-7 20 0 28l27 27c8 7 20 7 28 0z m45 45c3-4 6-10 6-16 0-6-2-12-6-16-4-3-10-6-16-6-6 0-12 2-16 6-4 5-6 10-6 16 0 6 2 12 6 16 5 4 10 6 16 6 6 0 12-2 16-6z"/>
|
|
||||||
<glyph glyph-name="pin" unicode="" d="M505 365l-140 140c-9 9-23 9-32 0-1-1-42-43-26-98l-64-63c-35 11-124 29-191-37-9-9-9-23 0-32l96-96-141-141c-9-9-9-23 0-32 4-4 10-6 15-6 6 0 11 2 16 7l141 141 96-96c4-4 10-6 16-6 5 0 11 2 15 6 66 67 48 157 37 191l64 64c54-16 96 25 98 26 9 9 9 23 0 32z m-94-12c-8 4-18 2-25-5l-83-83c-6-6-9-16-5-24 0 0 10-25 11-57 2-33-5-60-20-83l-94 94-95 94c60 40 137 10 140 9 8-4 18-2 24 5l84 83c7 7 8 17 4 25-8 17-5 32 0 44l103-103c-11-4-27-7-44 1z m-132-121c1-2 8-18 8-35 0-11-9-19-20-19 0 0 0 0 0 0-11 1-20 10-19 20 0 7-3 16-4 18-5 11 0 22 10 26 10 4 21 0 25-10z"/>
|
|
||||||
<glyph glyph-name="plus" unicode="" d="M403 253c0-14-11-25-25-25l-100 0 0-94c0-14-11-25-25-25-14 0-25 11-25 25l0 94-94 0c-14 0-25 11-25 25 0 14 11 25 25 25l94 0 0 100c0 14 11 25 25 25 14 0 25-11 25-25l0-100 100 0c14 0 25-11 25-25z"/>
|
|
||||||
<glyph glyph-name="power" unicode="" d="M256 248c-12 0-22 10-22 22l0 192c0 12 10 22 22 22 12 0 22-10 22-22l0-192c0-12-9-22-22-22z m211-8c0 82-45 155-117 191-11 5-24 1-30-10-6-11-1-25 10-30 57-29 93-87 93-151 0-93-75-168-167-168-92 0-167 75-167 168 0 65 36 122 93 151 11 6 16 19 10 30-6 11-19 16-30 10-72-36-117-109-117-191 0-117 94-212 211-212 117 0 211 95 211 212z"/>
|
|
||||||
<glyph glyph-name="preview" unicode="" d="M508 268c-4 6-94 138-252 138-158 0-248-132-252-138-5-7-5-17 0-25 4-5 94-137 252-137 158 0 248 132 252 138 5 7 5 17 0 24z m-252-118c-107 0-181 76-206 106 25 31 98 106 206 106 107 0 181-76 206-106-26-31-99-106-206-106z m13 197c-25 4-49-3-69-18-40-30-49-88-18-129 15-20 36-32 61-36 4 0 9-1 12-1 20 0 39 7 56 18 40 31 49 89 18 130-14 20-36 33-60 36z m22-138c-12-10-28-14-43-11-16 2-30 10-39 22-19 27-14 64 12 83 12 10 28 14 43 11 16-2 30-10 39-22 19-27 14-64-12-83z m-2 80c4-4 7-10 7-15 0-6-3-12-7-16-4-4-10-6-16-6-6 0-11 2-15 6-5 5-7 10-7 16 0 6 2 11 7 15 4 5 10 7 15 7 6 0 12-3 16-7z"/>
|
|
||||||
<glyph glyph-name="print" unicode="" d="M490 417l-112 0 0 67c0 10-5 17-13 17l-218 0c-8 0-13-7-13-17l0-67-112 0c-12 0-22-9-22-21l0-256c0-12 10-23 22-23l82 0-13-87c-1-6 0-12 4-17 4-4 9-7 15-7l292 0c6 0 11 3 15 8 4 4 6 10 5 15l-14 88 82 0c12 0 22 11 22 23l0 256c0 12-10 21-22 21z m-323 50l178 0 0-50-178 0z m-35-422l22 139 204 0 22-139z m335 116l-66 0-7 46c-2 9-9 16-19 16l-238 0c-10 0-18-7-20-16l-6-46-66 0 0 212 422 0z m-365 156c0 10 7 17 17 17l52 0c9 0 17-7 17-17 0-9-8-16-17-16l-52 0c-9 0-17 7-17 16z"/>
|
|
||||||
<glyph glyph-name="pulse" unicode="" d="M512 195c0-12-10-22-22-22l-105 0c-9 0-18 5-21 14l-17 47-54-184c-3-10-12-17-21-17 0 0-1 0-1 0-10 1-19 8-21 18l-72 311-43-173c-3-10-11-16-22-16l-91 0c-12 0-22 10-22 22 0 12 10 22 22 22l74 0 61 245c3 10 12 17 22 17 10 0 19-8 22-18l73-318 50 169c3 10 12 16 21 16 10 1 18-5 22-14l34-97 89 0c12 0 22-10 22-22z"/>
|
|
||||||
<glyph glyph-name="question" unicode="" d="M339 370c18-20 26-47 22-76-6-54-45-73-80-73-2 0-3 0-3 0l0-13c0-12-10-22-22-22-12 0-22 10-22 22l0 18c0 18 8 40 47 40 22 0 33 11 36 33 1 8 1 27-12 42-11 11-28 17-51 17-50 0-52-32-52-36 0-12-10-22-22-22-12 0-23 10-23 22 0 22 18 81 97 81 46 0 72-18 85-33z m-85-203c-7 0-14-3-19-8-5-5-8-13-8-20 0-7 2-14 8-19 5-5 12-9 19-9 8 0 15 3 20 9 5 5 8 12 8 19 0 7-3 15-8 20-5 5-12 8-20 8z m258 89c0-141-115-256-256-256-141 0-256 115-256 256 0 141 115 256 256 256 141 0 256-115 256-256z m-45 0c0 117-94 211-211 211-117 0-211-94-211-211 0-117 94-211 211-211 117 0 211 94 211 211z"/>
|
|
||||||
<glyph glyph-name="reply" unicode="" d="M399 269c-41 40-98 63-165 67l0 59c0 9-7 17-15 21-9 3-19 1-25-5l-137-139c-9-9-9-23 0-32l137-139c6-6 16-8 25-5 8 4 15 12 15 21l0 60c44 1 149-3 187-71 4-7 11-11 19-11 2 0 4 0 6 0 10 3 17 11 17 22-1 3-1 88-64 152z m-191-49c-11-1-19-10-19-22l0-27-83 85 83 85 0-27c0-12 9-22 21-22 120 0 171-58 192-107-78 47-188 36-194 35z"/>
|
|
||||||
<glyph glyph-name="reply-all" unicode="" d="M449 269c-41 40-98 63-165 67l0 59c0 9-7 17-15 21-9 3-19 1-25-5l-138-139c-8-9-9-23 0-32l137-139c6-6 17-8 26-5 8 4 15 12 15 21l0 60c44 1 149-3 187-71 4-7 11-11 19-11 1 0 3 0 5 0 10 3 18 11 18 22-1 3 0 88-64 152z m-191-49c-11-1-19-10-19-22l0-27-83 85 83 85 0-27c0-12 9-22 21-22 120 0 171-58 192-107-78 47-188 36-194 35z m-83-88c9-8 9-22 0-31-4-5-10-7-15-7-6 0-12 2-16 7l-137 139c-8 9-8 23 0 31l137 139c9 9 23 9 31 0 9-9 9-23 0-32l-122-122z"/>
|
|
||||||
<glyph glyph-name="return" unicode="" d="M456 332l0-221c0-12-10-22-22-22l-328 0c-12 0-22 10-22 22 0 13 10 23 22 23l306 0 0 178-280 0 31-32c8-8 8-23 0-32-5-4-11-6-16-6-6 0-11 2-16 6l-69 69c-4 4-6 10-6 15 0 6 2 12 6 16l69 68c9 9 23 9 32 0 9-9 8-22 0-31l-31-29 302 0c12 0 22-12 22-24z"/>
|
|
||||||
<glyph glyph-name="retweet" unicode="" d="M505 182l-69-69c-5-4-10-7-16-7-5 0-12 3-15 7l-71 69c-9 9-9 23-1 31 9 9 23 9 31 0l31-32 0 147-195 0c-12 0-22 10-22 23 0 12 10 22 22 22l220 0c12 0 20-10 20-22l0-169 33 32c9 9 24 8 33 0 8-9 8-23-1-32z m-193-32l-195 0 0 148 30-32c5-4 10-7 16-7 5 0 11 3 15 7 9 9 8 23 0 31l-70 70c-9 8-23 8-32 0l-69-69c-9-9-9-23 0-31 9-9 24-9 33 0l33 31 0-169c0-12 7-23 20-23l220 0c12 0 22 10 22 23 0 12-11 21-23 21z"/>
|
|
||||||
<glyph glyph-name="rocket" unicode="" d="M510 490c-1 11-9 20-20 21-141 11-242-57-305-143-34 11-71 7-105-12-33-18-61-49-78-87-4-9-3-19 5-26 6-6 17-8 25-3 36 19 76 15 100-9l98-98c0 0 0-1 0-1 24-23 28-64 9-99-4-9-2-19 4-26 4-4 10-6 16-6 3 0 6 0 9 2 38 18 69 45 88 78 19 34 23 71 11 106 25 18 48 38 67 61 59 67 85 149 76 242z m-435-194c24 23 54 38 85 32-9-15-16-31-23-46-18 10-40 15-62 14z m222-221c0 22-5 44-15 63 16 7 32 14 47 23 5-32-8-62-32-86z m-45 99l-78 79c39 105 137 217 293 214 5-186-148-267-215-293z m144 222c7-6 11-16 11-25 0-10-4-19-11-26-6-7-16-11-25-11-10 0-19 4-26 11-7 7-11 16-11 26 0 9 4 19 11 25 7 7 16 11 26 11 9 0 19-4 25-11z m-313-231c-26-26-27-77-27-87 0-12 10-22 22-22 0 0 1 0 1 0 12 0 61 1 86 26 15 16 19 32 19 43 0 15-6 29-18 41-28 28-63 19-83-1z m51-51c-6-5-18-9-31-11 2 13 6 25 11 30 4 4 7 6 11 6 3 0 6-2 10-5 3-3 5-7 5-9-1-4-4-8-6-11z"/>
|
|
||||||
<glyph glyph-name="scale" unicode="" d="M263 161c0-12-10-22-23-22l-218 0c-12 0-22 10-22 22 0 13 10 23 22 23l218 0c13 0 23-10 23-23z m227 23l-19 0c-12 0-22-10-22-23 0-12 10-22 22-22l19 0c12 0 22 10 22 22 0 13-10 23-22 23z m-410 167c0 37 30 66 66 66 37 0 67-30 67-66 0-36-30-66-67-66-36 0-66 29-66 66z m44 0c0-12 10-22 22-22 13 0 23 10 23 22 0 12-10 22-23 22-12 0-22-10-22-22z m296-190c0-37-30-66-67-66-37 0-67 30-67 66 0 36 30 66 67 66 37 1 67-29 67-66z m-45 0c0 12-10 22-22 22-12 0-22-10-22-22 0-12 10-22 22-22 12 0 22 10 22 22z m-353 167l13 0c12 0 22 10 22 23 0 12-10 22-22 22l-13 0c-12 0-22-10-22-22 0-13 10-23 22-23z m490 23c0 12-10 22-22 22l-227 0c-12 0-22-10-22-22 0-13 10-23 22-23l227 0c12 0 22 10 22 23z"/>
|
|
||||||
<glyph glyph-name="search" unicode="" d="M322 500c-95 0-173-79-173-174 0-41 14-78 37-108l-164-166c-9-10-9-25 0-35 5-5 11-7 18-7 6 0 12 2 17 7l164 166c28-20 63-32 100-32 95 0 173 78 173 174 0 96-77 175-172 175z m0-305c-71 0-128 58-128 130 0 72 57 130 128 130 70 0 128-58 128-130 0-72-58-130-128-130z m86 128c-1-10-10-17-19-17-1 0-2 0-3 0-10 2-18 11-16 22 3 29-29 44-31 44-9 5-13 16-9 26 4 9 16 14 26 10 2-1 60-27 52-85z m-41-43c4-3 7-10 7-15 0-6-2-12-7-16-4-4-10-6-15-6-6 0-12 2-16 6-4 4-7 10-7 16 0 5 3 12 7 15 4 4 10 7 16 7 5 0 11-2 15-7z"/>
|
|
||||||
<glyph glyph-name="shopping-bag" unicode="" d="M444 372c-4 4-9 6-15 6l-56 0 0 10c0 66-54 118-116 118l-2 0c-62 0-116-52-116-118l0-10-56 0c-12 0-22-10-22-23l0-327c0-12 10-22 22-22l346 0c12 0 22 10 22 22l0 328c0 5-2 11-7 16z m-260 16c0 41 33 74 71 74l2 0c38 0 71-33 71-74l0-10-144 0z m222-338l-300 0 0 284 33 0 0-38c0-13 10-23 22-23 13 0 23 10 23 23l0 38 144 0 0-38c0-13 10-23 23-23 12 0 22 10 22 23l0 38 33 0z"/>
|
|
||||||
<glyph glyph-name="skip" unicode="" d="M461 189l-99-99c-5-5-11-8-18-8-6 0-12 3-17 8-10 9-10 25 0 35l56 56-316 0c-7 0-14 3-19 8-5 4-9 11-9 17l0 127c0 14 11 25 25 25 14 0 25-11 25-25l0-102 293 0-55 57c-10 9-10 25 0 35 9 9 25 9 35 0l99-99c10-10 10-26 0-35z m-393 188c7 0 14 3 19 8 5 5 9 12 9 20 0 7-3 14-9 19-5 5-12 8-19 8-7 0-15-3-20-8-5-5-8-12-8-19 0-8 3-15 8-20 5-4 13-8 20-8z"/>
|
|
||||||
<glyph glyph-name="stack" unicode="" d="M451 422c0 59-98 90-195 90-97 0-195-31-195-90 0 0 0-1 0-1 0 0 0-1 0-1l0-333c0-57 98-87 195-87 97 0 195 30 195 87l0 333c0 0 0 1 0 1 0 1 0 1 0 1z m-45-168c0-12-53-43-150-43-97 0-150 30-150 43l0 109c38-20 94-30 150-30 56 0 112 10 150 30z m-150 213c99 0 150-31 150-45 0-13-51-45-150-45-99 0-150 32-150 45 0 14 51 45 150 45z m0-422c-97 0-150 30-150 42l0 109c38-19 94-29 150-29 56 0 112 10 150 29l0-109c0-12-53-42-150-42z m95 228l0 28c0 10 9 19 19 19 11 0 20-9 20-19l0-28c0-10-9-19-20-19-10 0-19 8-19 19z"/>
|
|
||||||
<glyph glyph-name="star" unicode="" d="M393 22c-4 0-8 1-12 4l-125 81-125-81c-8-5-18-5-25 0-7 6-11 15-9 24l40 139-118 100c-7 5-10 15-7 24 3 9 11 14 20 15l141 10 63 139c3 8 11 13 20 13 9 0 17-5 20-13l63-139 141-10c9 0 17-6 20-15 3-9 0-18-7-24l-117-99 39-139c3-9 0-19-8-24-4-3-9-5-14-5z m-137 134c4 0 8-1 12-4l88-57-27 96c-2 9 0 18 7 23l86 73-99 8c-8 1-15 6-19 13l-48 106-48-106c-4-7-11-12-19-13l-99-7 86-73c7-6 9-15 7-23l-27-97 88 57c4 3 8 4 12 4z"/>
|
|
||||||
<glyph glyph-name="stopwatch" unicode="" d="M452 403c5-4 10-6 15-6 7 0 13 3 17 8 9 8 8 23-1 31l-29 26-29 27c-9 8-24 7-32-2-8-9-7-23 2-32l12-11-22-25c-25 19-55 33-87 40-1 7-4 15-9 22-6 8-17 17-39 18 0 0 0 0-1 0-19 0-30-8-36-15-7-8-10-18-11-25-103-22-180-113-180-222 0-125 102-228 227-228 126 0 227 102 227 228 0 59-22 112-58 153l22 25z m-203-348c-100 0-182 81-182 182 0 101 82 183 182 183 101 0 183-82 183-183 0-101-82-182-183-182z m39 182c0-21-18-38-39-38-21 0-38 17-38 38 0 13 6 25 17 31l0 90c0 13 10 23 22 23 13 0 23-10 23-23l0-90c11-6 15-18 15-31z"/>
|
|
||||||
<glyph glyph-name="store" unicode="" d="M223 203c0 11-9 20-20 20l-72 0c-11 0-20-9-20-20l0-72c0-11 9-20 20-20l72 0c11 0 20 9 20 20z m-73-19l34 0 0-34-34 0z m356 187l-50 50 0 58c0 12-10 22-22 22l-356 0c-12 0-22-10-22-22l0-58-50-50c-4-4-6-10-6-16l0-57c0-12 10-20 22-20l468 0c12 0 22 8 22 21l0 56c0 6-2 12-6 16z m-94 85l0-27-312 0 0 27z m55-133l-422 0 0 23 45 44 332 0 45-44z m12-90l0-200c0-12-10-22-23-22l-76 0c-12 0-22 9-22 21l0 118-52 0 0-117c0-12-10-22-23-22l-227 0c-12 0-23 10-23 22l0 200c0 12 10 22 23 22 12 0 22-10 22-22l0-177 184 0 0 119c0 12 9 20 21 20l97 0c12 0 20-8 20-20l0-119 34 0 0 177c0 12 10 22 22 22 12 0 23-10 23-22z"/>
|
|
||||||
<glyph glyph-name="suitcase" unicode="" d="M500 379c-8 8-19 11-29 11l-120 0 0 66c0 13-13 23-25 23l-140 0c-12 0-25-10-25-23l0-66-120 0c-23 0-41-17-41-39l0-276c0-23 18-42 41-42l429 0c23 0 41 19 41 42l0 275c1 11-3 21-11 29z m-133-34l0-267-222 0 0 267z m-161 89l100 0 0-44-100 0z m-161-89l66 0 0-267-66 0z m422-267l-66 0 0 267 66 0z"/>
|
|
||||||
<glyph glyph-name="swap" unicode="" d="M512 203c0-6-2-12-7-15l-103-104c-5-4-10-6-16-6-5 0-11 3-15 7-9 8-9 23 0 32l65 67-218 0c-12 0-22 10-22 22 0 12 10 22 22 22l218 0-65 64c-9 9-9 22 0 30 9 9 22 9 31 0l104-103c4-4 6-10 6-16z m-436 81l218 0c12 0 22 10 22 22 0 12-10 22-22 22l-218 0 65 67c9 9 9 24 0 32-9 9-22 9-31 1l-103-104c-5-3-7-9-7-15 0-6 2-12 7-16l103-103c5-5 10-7 16-7 5 0 11 2 15 7 9 9 9 21 0 30z"/>
|
|
||||||
<glyph glyph-name="tag" unicode="" d="M490 401l-329 0c-5 0-10-3-14-6l-139-122c-5-5-8-11-8-17 0-7 3-12 8-17l139-122c4-3 9-6 14-6l329 0c12 0 22 10 22 23l0 244c0 13-10 23-22 23z m-23-245l-297 0-114 100 114 100 297 0z m-316 126c7 6 17 10 26 10 9 0 19-4 26-10 6-7 10-17 10-26 0-9-4-19-10-26-7-6-17-10-26-10-9 0-19 4-26 10-6 7-10 17-10 26 0 9 4 19 10 26z"/>
|
|
||||||
<glyph glyph-name="tag-delete" unicode="" d="M490 401l-329 0c-5 0-10-3-14-6l-139-122c-5-5-8-11-8-17 0-7 3-12 8-17l139-122c4-3 9-6 14-6l329 0c12 0 22 10 22 23l0 244c0 13-10 23-22 23z m-23-245l-297 0-114 100 114 100 297 0z m-222 70l30 30-30 30c-7 8-7 20 0 27 8 8 20 8 28 0l30-30 30 30c8 8 20 8 27 0 8-7 8-20 0-27l-29-30 30-30c7-8 7-20 0-27-4-4-9-6-14-6-5 0-10 2-14 6l-30 30-30-30c-4-4-9-6-14-6-5 0-10 2-14 6-7 7-7 19 0 27z"/>
|
|
||||||
<glyph glyph-name="tags" unicode="" d="M419 225c0 6-3 12-7 15l-208 205c-4 4-9 6-14 6l-166 11c-7 0-13-2-17-7-5-4-8-10-7-17l11-163c0-6 2-11 6-15l208-204c5-4 10-6 16-6 6 0 11 2 16 6l155 153c4 4 7 10 7 16z m-178-121l-186 183-9 129 133-9 186-182z m-96 262c6-6 10-15 10-23 0-9-4-17-10-24-6-6-15-10-24-10-9 0-17 4-24 10-6 7-10 15-10 24 0 9 3 17 10 23 6 6 15 10 24 10 9 0 18-4 24-10z m367-141c0-5-2-10-6-14l-155-153c-4-3-9-5-14-5-5 0-10 2-14 5-7 8-7 20 0 28l142 138-195 191c-7 8-7 20 0 27 8 8 21 8 28 0l208-203c4-4 6-9 6-14z"/>
|
|
||||||
<glyph glyph-name="thumbs-down" unicode="" d="M179 512c70 0 178-23 205-42 6-4 9-11 9-18l0-218c0-6-3-13-8-17-2-1-41-32-81-54-51-28-86-67-94-92-11-30-25-71-71-71-22 0-39 12-49 33-19 44 1 104 35 151-23 5-50 12-67 17-30 10-51 32-55 59-4 28 10 57 40 78 22 58 59 151 86 166 10 6 28 8 50 8z m169-73c-42 17-172 36-197 26-12-11-45-86-68-149-2-4-5-8-8-11-19-12-28-27-27-39 2-10 11-18 24-23 28-9 97-24 98-24 8-1 14-7 17-15 3-8 1-16-5-21-50-54-59-110-50-132 3-6 5-6 7-6 11 0 16 7 28 41 13 39 60 85 115 115 26 15 53 34 66 44z m88 15l0-222c0-20 16-36 36-36 21 0 37 16 37 36l0 222c0 20-16 36-37 36-20 0-36-16-36-36z"/>
|
|
||||||
<glyph glyph-name="thumbs-up" unicode="" d="M333 0c-69 0-178 23-204 42-7 4-10 11-10 18l0 218c0 6 3 13 8 17 2 1 41 32 82 54 50 28 85 67 94 92 10 30 24 71 70 71 22 0 39-12 49-33 19-44-1-104-35-151 23-5 50-12 67-17 31-10 51-32 55-59 4-28-10-57-39-78-22-59-59-151-87-166-10-6-28-8-50-8z m-169 73c42-17 172-36 197-26 12 11 45 86 68 149 2 4 5 8 8 11 19 12 28 27 27 39-2 10-11 18-24 23-28 9-97 24-98 24-8 1-14 7-17 15-3 8-1 16 5 21 50 54 59 110 50 132-3 6-5 6-7 6-11 0-16-7-28-41-13-39-60-85-115-115-26-15-53-34-66-44z m-88-15l0 222c0 21-16 37-36 37-21 0-37-16-37-37l0-222c0-20 16-36 36-36 20 0 37 16 37 36z"/>
|
|
||||||
<glyph glyph-name="ticket" unicode="" d="M151 277l126-126c5-5 12-7 19-7 6 0 13 2 18 7l47 47c5 5 7 11 7 18 0 7-2 14-7 19l-126 126c-5 5-11 7-19 7-6 0-13-2-18-7l-47-47c-10-10-10-27 0-37z m65 55l116-116-36-36-116 116z m289-129l-302 302c-9 9-23 9-32 0l-42-42c-6-6-8-16-5-24 6-15 2-32-9-43-11-11-28-14-43-9-8 4-17 1-24-5l-42-42c-4-4-6-10-6-16 0-6 2-11 7-15l302-302c4-5 10-7 15-7 7 0 12 2 16 7l42 42c6 6 9 16 5 24-6 15-2 32 9 43 11 11 28 14 43 9 8-4 18-1 24 5l42 42c9 9 9 23 0 31z m-64-33c-28 6-56-2-76-23-21-20-29-49-24-76l-17-18-270 271 17 18c28-6 56 2 76 23 21 20 29 49 24 76l17 18 271-271z"/>
|
|
||||||
<glyph glyph-name="time-reverse" unicode="" d="M512 256c0-120-97-217-216-217-44 0-86 13-122 38-10 7-13 20-6 31 7 10 21 13 31 6 29-20 63-31 97-31 95 0 171 78 171 173 0 95-76 173-171 173-92 0-168-74-171-167l51 52c9 9 23 9 32 0 9-8 9-22 0-31l-85-85c-4-5-10-7-16-7-6 0-11 2-15 7l-85 85c-9 9-9 23 0 32 9 9 22 9 31 0l43-43c7 112 101 201 215 201 119 0 216-97 216-217z m-217 126c-12 0-22-10-22-22l0-104c0-6 2-12 7-16l48-47c4-5 10-7 16-7 5 0 12 2 16 7 8 8 8 22-1 31l-42 41 0 95c0 12-10 22-22 22z"/>
|
|
||||||
<glyph glyph-name="to-do" unicode="" d="M139 413l0 71c0 16 12 28 28 28 16 0 28-12 28-28l0-71c0-16-12-28-28-28-16 0-28 12-28 28z m206-28c16 0 28 12 28 28l0 71c0 16-12 28-28 28-16 0-28-12-28-28l0-71c0-16 12-28 28-28z m-188-96l198 0c12 0 22 10 22 23 0 12-10 22-22 22l-198 0c-12 0-22-10-22-22 0-13 10-23 22-23z m310 184l-46 0c-12 0-22-10-22-22 0-12 10-22 22-22l24 0 0-379-378 0 0 379 24 0c12 0 22 10 22 22 0 12-10 22-22 22l-46 0c-13 0-23-12-23-24l0-421c0-12 10-22 23-22l422 0c13 0 23 10 23 22l0 421c0 12-10 24-23 24z m-229-44l36 0c13 0 23 10 23 22 0 12-10 22-23 22l-36 0c-13 0-23-10-23-22 0-12 10-22 23-22z m-81-240l198 0c12 0 22 10 22 22 0 13-10 23-22 23l-198 0c-12 0-22-10-22-23 0-12 10-22 22-22z"/>
|
|
||||||
<glyph glyph-name="toggles" unicode="" d="M467 240l0-218c0-12-10-22-22-22-12 0-22 10-22 22l0 218c0 13 10 23 22 23 12 0 22-10 22-23z m-22 209c12 0 22 10 22 22l0 19c0 12-10 22-22 22-12 0-22-10-22-22l0-19c0-12 10-22 22-22z m-312-193c0-37-30-67-66-67-36 0-67 30-67 67 0 37 30 67 66 67 36 0 67-30 67-67z m-45 0c0 12-10 22-21 22-12 0-22-10-22-22 0-12 10-22 21-22 12 0 22 10 22 22z m234-110c0-36-30-66-66-66-36 0-66 30-66 66 0 37 30 67 66 67 36 0 66-29 66-67z m-44 0c0 13-10 23-22 23-12 0-22-10-22-23 0-12 10-22 22-22 12 0 22 10 22 22z m234 207c0-37-30-67-66-67-36 0-66 30-66 67 0 37 30 67 66 67 36 0 66-30 66-67z m-45 0c0 12-10 22-21 22-12 0-22-10-22-22 0-12 10-22 22-22 11 0 21 9 21 22z m-211-296c-12 0-22-10-22-22l0-13c0-12 10-22 22-22 12 0 22 10 22 22l0 13c0 12-10 22-22 22z m0 184c12 0 22 10 22 22l0 227c0 12-10 22-22 22-12 0-22-10-22-22l0-227c0-12 10-22 22-22z m-189-81c-12 0-22-10-22-23l0-115c0-12 10-22 22-22 12 0 22 10 22 22l0 115c0 13-10 23-22 23z m0 191c12 0 22 10 22 22l0 117c0 12-10 22-22 22-12 0-22-10-22-22l0-117c0-12 10-22 22-22z"/>
|
|
||||||
<glyph glyph-name="trash" unicode="" d="M436 343l-17-322c0-12-11-21-22-21l-282 0c-11 0-22 9-22 21l-17 322c-1 12 9 23 21 23 12 1 23-9 23-21l16-300 240 0 16 300c1 12 11 22 24 21 11 0 21-11 20-23z m59 74c0-12-10-22-22-22l-434 0c-12 0-22 10-22 22 0 13 10 23 22 23l122 0 0 50c0 10 8 16 18 16l154 0c10 0 18-6 18-16l0-50 122 0c12 0 22-10 22-23z m-295 23l112 0 0 27-112 0z m10-362c11 0 19 10 19 21l-5 240c0 11-9 20-20 20-11 0-20-9-19-20l5-241c0-11 9-20 20-20z m92 0c10 0 19 9 19 19l6 241c0 10-9 20-19 20-11 0-20-9-20-19l-6-240c0-12 9-21 20-21-1 0-1 0 0 0z"/>
|
|
||||||
<glyph glyph-name="trophy" unicode="" d="M301 355l0 50c0 10 8 19 19 19 11 0 19-9 19-19l0-50c0-11-8-19-19-19-11 0-19 8-19 19z m18-76c6 0 12 3 15 7 4 5 7 10 7 16 0 6-2 11-7 15-3 5-10 7-15 7-6 0-12-2-16-7-4-4-6-10-6-15 0-6 2-12 6-16 4-4 10-7 16-7z m147 22c-16-18-37-28-61-32-13-75-66-113-127-120l0-82 48 0c12 0 22-10 22-22 0-13-10-23-22-23l-140 0c-12 0-22 10-22 23 0 12 10 22 22 22l48 0 0 82c-61 7-114 45-126 120-25 4-45 14-62 32-46 47-44 128-43 131 0 10 9 19 19 19l84 0 0 16c0 13 9 23 21 23l258 0c12 0 21-10 21-23l0-16 84 0c10 0 19-9 19-19 0-3 2-85-43-131z m-392 26c9-9 21-15 32-18l0 103-64 0c3-22 9-61 32-85z m288 118l-212 0 0-144c0-81 55-109 106-109 51 0 106 29 106 109z m76-118c22 22 29 57 32 85l-64 0 0-103c11 3 23 9 32 18z"/>
|
|
||||||
<glyph glyph-name="upload" unicode="" d="M495 185l0-152c0-15-12-27-28-27l-422 0c-16 0-28 12-28 27l0 152c0 15 12 28 28 28 15 0 27-13 27-28l0-124 368 0 0 124c0 15 12 28 27 28 16 0 28-13 28-28z m-330 161l63 65 0-241c0-16 12-28 28-28 16 0 28 12 28 28l0 240 63-64c6-6 13-9 20-9 8 0 14 3 20 8 11 11 11 28 0 40l-111 113c-6 6-13 8-20 8-7 0-14-2-20-8l-111-113c-10-12-10-29 1-40 10-11 28-10 39 1z"/>
|
|
||||||
<glyph glyph-name="user" unicode="" d="M256 194c82 0 150 68 150 150 0 84-68 151-150 151-82 0-150-67-150-150 0-83 68-151 150-151z m0 257c58 0 105-48 105-106 0-58-47-106-105-106-58 0-105 48-105 106 0 58 47 106 105 106z m70-271c-8 2-16 0-22-5l-48-41-48 41c-7 5-14 7-22 5-31-10-186-64-186-141 0-12 10-22 22-22l468 0c12 0 22 10 22 22 0 77-155 131-186 141z m-270-119c25 26 84 55 133 72l53-45c8-7 20-7 28 0l53 45c49-17 108-46 133-72z"/>
|
|
||||||
<glyph glyph-name="user-group" unicode="" d="M197 210c65 0 118 53 118 117 0 65-53 118-118 118-65 0-118-53-118-118 1-64 53-117 118-117z m0 191c41 0 73-33 73-73 0-40-32-73-73-73-41 0-73 33-73 73 0 40 33 73 73 73z m53-202c-6 2-12 1-18-2l-35-21-35 21c-6 3-12 4-18 2-34-11-144-50-144-110 0-12 10-22 22-22l350 0c12 0 22 10 22 22 0 60-110 99-144 110z m-188-88c19 15 51 30 85 43l38-23c8-5 16-5 23 0l38 23c34-12 66-28 85-43z m444 17c0-9-7-17-16-17l-75 0c-9 0-17 8-17 17 0 9 8 17 17 17l50 0c-9 11-22 20-39 29-8 4-11 14-6 22 4 8 14 11 22 7 24-13 64-40 64-75z m-93 147c0 24-20 44-44 44-6 0-12-1-17-3-9-4-19 0-22 8-3 9 1 19 9 22 9 4 19 6 30 6 43 0 77-34 77-77 0-43-35-77-77-77-22 0-43 9-58 26-6 6-5 17 2 23 6 6 17 6 23-2 8-9 21-15 34-15 23 1 43 21 43 45z"/>
|
|
||||||
<glyph glyph-name="user-id" unicode="" d="M347 203c43 0 78 35 78 78 0 43-35 78-78 78-43 0-78-35-78-78 0-43 35-78 78-78z m0 123c24 0 44-20 44-45 0-24-20-44-44-44-25 0-45 20-45 44 0 25 20 45 45 45z m-260-9c0 10 8 17 17 17l97 0c9 0 17-7 17-17 0-9-8-16-17-16l-97 0c-9 0-17 7-17 16z m114-78l-97 0c-9 0-17 8-17 17 0 9 8 17 17 17l97 0c9 0 17-8 17-17 0-9-8-17-17-17z m-25-44c0-10-7-17-16-17l-56 0c-9 0-17 7-17 17 0 9 8 16 17 16l56 0c9 0 16-7 16-16z m336 191c0 20-17 37-37 37l-438 0c-20 0-37-17-37-37l0-260c0-20 17-37 37-37l438 0c20 0 37 17 37 37z m-467-8l422 0 0-232c-23 24-65 39-81 45-3 1-7 1-11 0l-28-10-29 10c-3 1-7 0-11-1-18-6-70-23-91-56l-171 0z m220-244c13 11 30 16 48 23l28-10c3-1 8-1 11 0l29 9c17-6 34-12 47-23l-163 0z"/>
|
|
||||||
<glyph glyph-name="vibrate" unicode="" d="M6 371c-9 10-8 26 2 34 90 75 182 49 260 14 82-38 148-34 203 11 10 9 26 7 35-4 9-10 7-26-3-34-39-32-83-49-132-49-38 0-80 10-124 31-77 35-142 48-206-7-11-8-27-7-35 4z m465-81c-54-45-121-48-203-11-78 35-169 62-259-14-11-8-12-24-3-34 9-11 25-12 35-3 65 54 129 42 207 6 44-20 85-30 124-30 48 0 92 16 131 48 11 9 12 25 3 35-8 10-24 12-35 3z m0-140c-54-45-121-48-203-11-78 36-169 62-259-13-11-9-12-25-3-35 9-10 25-11 35-3 65 54 129 42 207 7 44-20 85-31 124-31 48 0 92 16 131 48 11 9 12 25 3 35-8 10-24 12-35 3z"/>
|
|
||||||
<glyph glyph-name="view-apps" unicode="" d="M111 356c-10 0-20 5-28 12-7 7-11 17-11 27 0 10 5 20 11 28 8 7 18 11 28 11 10 0 20-4 28-11 7-7 11-17 11-28 0-10-4-20-11-27-8-7-18-12-28-12z m172 12c8 7 12 17 12 27 0 10-4 20-12 28-7 7-17 11-27 11-10 0-21-4-28-11-7-7-11-17-11-28 0-10 4-20 11-27 7-7 17-12 28-12 10 0 20 5 27 12z m145 0c7 7 12 17 12 27 0 10-5 20-12 28-7 7-17 11-27 11-10 0-21-4-28-11-7-7-11-17-11-28 0-10 4-20 11-27 7-7 17-12 28-12 10 0 20 5 27 12z m-289-139c7 7 11 17 11 27 0 10-4 20-11 28-8 7-18 11-28 11-10 0-20-4-28-11-7-7-11-17-11-28 0-10 5-20 11-27 8-8 18-12 28-12 10 0 20 4 28 12z m144 0c8 7 12 17 12 27 0 10-4 20-12 28-7 7-17 11-27 11-10 0-21-4-28-11-7-7-11-17-11-28 0-10 4-20 11-27 7-8 17-12 28-12 10 0 20 4 27 12z m145 0c7 7 12 17 12 27 0 10-5 20-12 28-7 7-17 11-27 11-10 0-21-4-28-11-7-7-11-17-11-28 0-10 4-20 11-27 7-8 17-12 28-12 10 0 20 4 27 12z m-289-139c7 7 11 17 11 27 0 10-4 20-11 28-8 7-18 11-28 11-10 0-20-5-28-11-7-8-11-18-11-28 0-10 5-20 11-27 8-8 18-12 28-12 10 0 20 4 28 12z m144 0c8 7 12 17 12 27 0 10-4 20-12 28-7 7-17 11-27 11-10 0-21-5-28-11-7-8-11-18-11-28 0-10 4-20 11-27 7-8 17-12 28-12 10 0 20 4 27 12z m145 0c7 7 12 17 12 27 0 10-5 20-12 28-7 7-17 11-27 11-10 0-21-5-28-11-7-8-11-18-11-28 0-10 4-20 11-27 7-8 17-12 28-12 10 0 20 4 27 12z"/>
|
|
||||||
<glyph glyph-name="view-list" unicode="" d="M142 434c0 16 13 28 28 28l309 0c15 0 27-12 27-28 0-15-12-28-27-28l-309 0c-15 0-28 13-28 28z m337-150l-309 0c-15 0-28-12-28-28 0-16 13-28 28-28l309 0c15 0 27 12 27 28 0 16-12 28-27 28z m0-178l-309 0c-15 0-28-13-28-28 0-16 13-28 28-28l309 0c15 0 27 12 27 28 0 15-12 28-27 28z m-429 187c-22 0-39-18-39-40 0-21 17-39 39-39 22 0 39 18 39 39 0 22-18 40-39 40z m0 180c-22 0-39-18-39-39 0-22 17-40 39-40 22 0 39 18 39 40 0 21-18 39-39 39z m0-355c-22 0-39-18-39-40 0-21 17-39 39-39 22 0 39 18 39 39 0 22-18 40-39 40z"/>
|
|
||||||
<glyph glyph-name="view-list-large" unicode="" d="M482 282l-249 0c-17 0-30 14-30 30l0 75c0 17 13 30 30 30l248 0c17 0 30-13 30-30l0-75c1-16-12-30-29-30z m-235 45l220 0 0 46-220 0z m235-232l-249 0c-17 0-30 13-30 30l0 75c0 16 13 30 30 30l248 0c17 0 30-14 30-30l0-75c1-17-12-30-29-30z m-235 44l220 0 0 46-220 0z m-115 143l-101 0c-17 0-31 14-31 31l0 73c0 17 14 31 31 31l101 0c17 0 31-14 31-31l0-73c0-17-14-31-31-31z m-87 45l74 0 0 46-74 0z m87-232l-101 0c-17 0-31 14-31 31l0 73c0 17 14 31 31 31l101 0c17 0 31-14 31-31l0-73c0-17-14-31-31-31z m-87 44l74 0 0 46-74 0z"/>
|
|
||||||
<glyph glyph-name="view-thumb" unicode="" d="M194 285l-152 0c-17 0-31 14-31 32l0 119c0 18 14 31 31 31l152 0c17 0 31-13 31-31l0-119c0-18-14-32-31-32z m-138 45l125 0 0 93-125 0z m414-45l-152 0c-17 0-31 14-31 32l0 119c0 18 14 31 31 31l152 0c17 0 31-13 31-31l0-119c0-18-14-32-31-32z m-139 45l125 0 0 93-125 0z m-137-285l-152 0c-17 0-31 13-31 31l0 119c0 18 14 32 31 32l152 0c17 0 31-14 31-32l0-119c0-18-14-31-31-31z m-138 44l125 0 0 93-125 0z m414-44l-152 0c-17 0-31 13-31 31l0 119c0 18 14 32 31 32l152 0c17 0 31-14 31-32l0-119c0-18-14-31-31-31z m-139 44l125 0 0 93-125 0z"/>
|
|
||||||
<glyph glyph-name="volume-full" unicode="" d="M210 488c-9 3-17 2-24-5l-110-110-54 0c-12 0-22-10-22-22l0-190c0-12 10-22 22-22l55 0 109-110c5-5 10-7 16-7 3 0 5 1 8 2 8 3 13 12 13 21l0 422c0 9-5 18-13 21z m-32-389l-77 78c-5 4-9 7-15 7l-41 0 0 144 41 0c6 0 10 3 15 7l77 78z m118 63c-4-5-11-7-17-7-5 0-10 1-15 5-9 9-10 23-1 31 55 63 5 123 0 130-9 9-8 23 1 31 9 8 24 7 32-2 29-32 67-113 0-188z m67-60c-4-5-10-7-16-7-5 0-11 2-15 6-9 8-10 22-2 31 110 123 4 243 0 248-8 10-7 23 2 32 9 8 23 7 31-2 2-2 136-156 0-308z m71-45c-5-5-11-7-17-7-5 0-11 2-15 6-9 8-10 22-2 31 62 70 82 148 57 231-19 63-56 106-57 106-8 9-7 23 2 31 9 9 23 7 32-1 1-2 175-200 0-397z"/>
|
|
||||||
<glyph glyph-name="volume-low" unicode="" d="M299 488c-8 3-17 2-24-5l-109-110-55 0c-12 0-22-10-22-22l0-190c0-12 10-22 22-22l55 0 110-110c4-5 10-7 16-7 2 0 4 1 7 2 8 3 13 12 13 21l0 422c0 9-5 18-13 21z m-32-389l-77 78c-5 4-9 7-15 7l-41 0 0 144 41 0c6 0 10 3 14 7l78 78z m119 63c-5-5-11-7-17-7-6 0-11 1-15 5-9 9-10 23-2 31 58 64 3 127 0 130-8 8-7 23 2 31 9 8 23 7 31-2 30-32 67-113 1-188z"/>
|
|
||||||
<glyph glyph-name="volume-medium" unicode="" d="M254 488c-9 3-18 2-24-5l-109-110-54 0c-12 0-22-10-22-22l0-190c0-12 10-22 22-22l54 0 109-110c5-5 10-7 16-7 3 0 5 1 8 2 8 3 13 12 13 21l0 422c0 9-5 18-13 21z m-31-389l-78 78c-4 4-9 7-15 7l-41 0 0 144 41 0c6 0 11 3 15 7l78 78z m117 63c-4-5-11-7-17-7-5 0-10 1-15 5-9 9-10 23-1 31 55 63 5 123 0 130-9 9-8 23 2 31 9 8 23 7 31-2 29-32 66-113 0-188z m67-60c-5-5-11-7-17-7-5 0-10 2-15 6-9 8-10 22-2 31 110 122 5 243 0 248-8 10-7 23 2 31 10 9 23 8 31-1 2-2 137-156 1-308z"/>
|
|
||||||
<glyph glyph-name="volume-off" unicode="" d="M224 488c-8 3-18 1-25-5l-107-110-53 0c-12 0-22-10-22-22l0-190c0-12 10-22 22-22l53 0 107-110c4-5 10-7 16-7 3 0 6 1 9 2 9 3 15 12 15 21l0 422c0 9-6 18-15 21z m-29-389l-77 78c-4 4-11 7-17 7l-40 0 0 144 40 0c6 0 13 3 18 7l76 78z m294 90c9-9 9-23 0-32-5-3-10-6-16-6-6 0-12 3-16 7l-64 66-64-66c-5-4-10-7-16-7-6 0-11 3-16 6-9 9-9 23 0 32l65 67-65 67c-8 9-8 23 1 32 9 8 23 8 31-1l64-66 64 66c9 9 23 9 32 1 9-9 9-23 1-32l-66-67z"/>
|
|
||||||
<glyph glyph-name="wallet" unicode="" d="M402 238c8-8 11-18 11-28 0-10-3-20-11-27-7-8-17-12-27-12-10 0-20 4-28 12-8 7-11 17-11 27 0 10 4 20 11 28 7 7 17 11 28 11 10 0 20-4 27-11z m104 86l0-246c0-25-20-45-45-45l-403 0c-29 0-52 24-52 53l0 326c0 37 30 67 66 67l308 0c31 0 54-25 54-56l0-33 10 0c35 0 62-31 62-66z m-459 88c0-12 10-22 22-22l321 0 0 34c0 6-5 10-10 10l-311 0c-12 0-22-10-22-22z m415-88c0 10-8 21-18 21l-385 0c-5 0-9-7-9-12l0-247c0-4 4-8 8-8l403 0c1 0 1 0 1 0z"/>
|
|
||||||
<glyph glyph-name="warning" unicode="" d="M490 28l-468 0c-8 0-15 4-19 11-4 7-4 15 0 22l234 412c3 7 11 11 19 11 8 0 16-4 19-11l234-412c4-6 4-15 0-22-4-7-11-11-19-11z m-429 44l391 0-196 345z m217 133l0 104c0 12-10 22-22 22-12 0-22-10-22-22l0-104c0-12 10-22 22-22 12 0 22 10 22 22z m-3-92c5 5 9 12 9 19 0 8-3 15-9 20-5 5-12 8-19 8-7 0-14-3-19-8-5-5-9-12-9-20 0-7 3-14 9-19 5-5 12-8 19-8 7 0 14 3 19 8z"/>
|
|
||||||
<glyph glyph-name="web" unicode="" d="M256 512c-141 0-256-115-256-256 0-141 115-256 256-256 141 0 256 115 256 256 0 141-115 256-256 256z m21-466c-2 0-3 0-4-1l0 121c29 0 55 1 79 3-21-65-61-109-75-123z m-42 0c-15 15-54 58-75 123 24-2 50-3 79-3l0-121c-1 0-2 1-4 1z m-190 210c0 14 1 28 3 41 13 2 36 6 69 9-3-16-5-33-5-51 0-17 2-34 4-50-32 4-56 7-68 9-2 14-3 28-3 42z m101 0c0 19 3 37 6 53 26 2 54 4 87 4l0-114c-32 1-61 2-88 4-2 16-5 34-5 53z m130 210c15-15 53-59 75-123-23 2-49 3-78 3l0 121c1 0 2-1 3-1z m-37 1l0-121c-29 0-55-1-78-3 21 64 60 108 74 123 2 0 3 1 4 1z m34-268l0 114c32-1 61-2 87-4 3-16 6-34 6-53 0-19-2-37-5-53-26-2-55-3-88-4z m122 107c32-3 56-7 68-9 3-13 4-27 4-41 0-14-1-28-3-41-13-2-36-6-69-9 3 16 4 33 4 51 0 16-2 34-4 49z m58 27c-16 2-38 5-66 8-14 47-37 86-56 113 56-21 100-66 122-121z m-272 121c-20-27-42-65-56-113-28-2-50-5-66-8 22 55 67 100 122 121z m-122-275c16-2 38-5 66-8 13-47 35-86 55-113-55 22-99 66-121 121z m273-121c20 27 42 65 55 113 28 2 50 5 66 8-22-55-66-99-121-121z"/>
|
|
||||||
<glyph glyph-name="weight" unicode="" d="M452 339c-2 22-21 39-44 39l-41 0 0 10c0 66-48 118-110 118l-2 0c-62 0-110-52-110-118l0-10-41 0c-23 0-41-17-44-39l-32-308c-1-7 1-13 5-18 5-5 11-7 17-7l412 0c6 0 12 2 17 7 4 4 6 11 5 17z m-263 49c0 41 29 74 66 74l2 0c37 0 66-33 66-74l0-10-134 0z m-114-338l29 284 303 0 29-284z"/>
|
|
||||||
<glyph glyph-name="wifi" unicode="" d="M424 286c11-11 12-28 1-39-5-6-13-9-20-9-7 0-14 2-19 7-124 113-257 6-262 2-12-10-30-9-39 3-10 12-9 29 3 39 61 50 208 114 336-3z m-166-155c-14 0-28-5-38-15-10-10-15-24-15-38 0-13 5-27 15-37 10-10 24-15 38-15 14 0 27 5 37 15 10 10 16 24 16 37 0 14-6 28-16 38-10 10-23 15-37 15z m245 231c-132 115-260 109-344 83-89-27-148-80-150-83-11-11-12-28-1-39 10-11 28-12 39-1 1 0 52 47 129 70 102 32 200 7 290-72 5-4 12-7 19-7 8 0 15 4 21 10 9 11 8 29-3 39z m-339-152c-12-10-14-27-4-39 9-12 27-14 39-5 2 2 61 48 111 1 6-5 12-7 19-7 7 0 15 3 20 9 11 11 11 29-1 39-68 62-150 28-184 2z"/>
|
|
||||||
<glyph glyph-name="wrong" unicode="" d="M437 437c-100 99-262 99-362 0-100-100-100-262 0-362 50-51 115-76 180-76 66 0 132 25 181 76 101 100 101 262 1 362z m-331-331c-77 78-82 200-15 283l298-298c-83-67-205-62-283 15z m315 17l-298 298c38 31 86 46 133 46 54 0 109-20 150-61 77-78 82-200 15-283z"/>
|
|
||||||
<glyph glyph-name="zoom-in" unicode="" d="M505 43l-194 191c23 29 37 66 37 105 0 96-78 173-174 173-97 0-174-77-174-173 0-95 78-172 174-172 38 0 73 12 101 32l195-192c5-5 11-7 17-7 7 0 13 2 18 7 9 10 9 26 0 36z m-460 296c0 71 57 128 129 128 72 0 130-57 130-128 0-70-59-128-130-128-71 0-129 58-129 128z m216-2c0-11-9-20-19-20l-47 0 0-44c0-11-9-20-20-20-10 0-19 9-19 20l0 44-50 0c-10 0-19 9-19 20 0 10 9 19 19 19l50 0 0 51c0 10 9 19 19 19 11 0 20-9 20-19l0-51 47 0c11 0 19-9 19-19z"/>
|
|
||||||
<glyph glyph-name="zoom-out" unicode="" d="M505 43l-194 191c23 29 37 66 37 105 0 96-78 173-174 173-97 0-174-77-174-173 0-95 78-172 174-172 38 0 73 12 101 32l195-192c5-5 11-7 17-7 7 0 13 2 18 7 9 10 9 26 0 36z m-460 296c0 71 57 128 129 128 72 0 130-57 130-128 0-70-59-128-130-128-71 0-129 58-129 128z m216-2c0-11-9-20-19-20l-136 0c-10 0-19 9-19 20 0 10 9 19 19 19l136 0c11 0 19-9 19-19z"/>
|
|
||||||
</font></defs></svg>
|
|
||||||
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 699 KiB |
@@ -1,803 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!--
|
|
||||||
Font Awesome Free 5.13.0 by @fontawesome - https://fontawesome.com
|
|
||||||
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
|
||||||
-->
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
|
|
||||||
<metadata>
|
|
||||||
Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020
|
|
||||||
By Robert Madole
|
|
||||||
Copyright (c) Font Awesome
|
|
||||||
</metadata>
|
|
||||||
<defs>
|
|
||||||
<font id="FontAwesome5Free-Regular" horiz-adv-x="512" >
|
|
||||||
<font-face
|
|
||||||
font-family="Font Awesome 5 Free Regular"
|
|
||||||
font-weight="400"
|
|
||||||
font-stretch="normal"
|
|
||||||
units-per-em="512"
|
|
||||||
panose-1="2 0 5 3 0 0 0 0 0 0"
|
|
||||||
ascent="448"
|
|
||||||
descent="-64"
|
|
||||||
bbox="-0.0663408 -64.0662 640.01 448.1"
|
|
||||||
underline-thickness="25"
|
|
||||||
underline-position="-50"
|
|
||||||
unicode-range="U+0020-F5C8"
|
|
||||||
/>
|
|
||||||
<missing-glyph />
|
|
||||||
<glyph glyph-name="heart" unicode=""
|
|
||||||
d="M458.4 383.7c75.2998 -63.4004 64.0996 -166.601 10.5996 -221.3l-175.4 -178.7c-10 -10.2002 -23.2998 -15.7998 -37.5996 -15.7998c-14.2002 0 -27.5996 5.69922 -37.5996 15.8994l-175.4 178.7c-53.5996 54.7002 -64.5996 157.9 10.5996 221.2
|
|
||||||
c57.8008 48.7002 147.101 41.2998 202.4 -15c55.2998 56.2998 144.6 63.5996 202.4 15zM434.8 196.2c36.2002 36.8994 43.7998 107.7 -7.2998 150.8c-38.7002 32.5996 -98.7002 27.9004 -136.5 -10.5996l-35 -35.7002l-35 35.7002
|
|
||||||
c-37.5996 38.2998 -97.5996 43.1992 -136.5 10.5c-51.2002 -43.1006 -43.7998 -113.5 -7.2998 -150.7l175.399 -178.7c2.40039 -2.40039 4.40039 -2.40039 6.80078 0z" />
|
|
||||||
<glyph glyph-name="star" unicode="" horiz-adv-x="576"
|
|
||||||
d="M528.1 276.5c26.2002 -3.7998 36.7002 -36.0996 17.7002 -54.5996l-105.7 -103l25 -145.5c4.5 -26.3008 -23.1992 -45.9004 -46.3994 -33.7002l-130.7 68.7002l-130.7 -68.7002c-23.2002 -12.2998 -50.8994 7.39941 -46.3994 33.7002l25 145.5l-105.7 103
|
|
||||||
c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2998l65.2998 132.4c11.7998 23.8994 45.7002 23.5996 57.4004 0l65.2998 -132.4zM388.6 135.7l100.601 98l-139 20.2002l-62.2002 126l-62.2002 -126l-139 -20.2002l100.601 -98l-23.7002 -138.4l124.3 65.2998
|
|
||||||
l124.3 -65.2998z" />
|
|
||||||
<glyph glyph-name="user" unicode="" horiz-adv-x="448"
|
|
||||||
d="M313.6 144c74.2002 0 134.4 -60.2002 134.4 -134.4v-25.5996c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v25.5996c0 74.2002 60.2002 134.4 134.4 134.4c28.7998 0 42.5 -16 89.5996 -16s60.9004 16 89.5996 16zM400 -16v25.5996
|
|
||||||
c0 47.6006 -38.7998 86.4004 -86.4004 86.4004c-14.6992 0 -37.8994 -16 -89.5996 -16c-51.2998 0 -75 16 -89.5996 16c-47.6006 0 -86.4004 -38.7998 -86.4004 -86.4004v-25.5996h352zM224 160c-79.5 0 -144 64.5 -144 144s64.5 144 144 144s144 -64.5 144 -144
|
|
||||||
s-64.5 -144 -144 -144zM224 400c-52.9004 0 -96 -43.0996 -96 -96s43.0996 -96 96 -96s96 43.0996 96 96s-43.0996 96 -96 96z" />
|
|
||||||
<glyph glyph-name="clock" unicode=""
|
|
||||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM317.8 96.4004l-84.8994 61.6992
|
|
||||||
c-3.10059 2.30078 -4.90039 5.90039 -4.90039 9.7002v164.2c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12v-141.7l66.7998 -48.5996c5.40039 -3.90039 6.5 -11.4004 2.60059 -16.7998l-18.8008 -25.9004c-3.89941 -5.2998 -11.3994 -6.5 -16.7998 -2.59961z
|
|
||||||
" />
|
|
||||||
<glyph glyph-name="list-alt" unicode=""
|
|
||||||
d="M464 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h416zM458 16c3.31152 0 6 2.68848 6 6v340c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-340
|
|
||||||
c0 -3.31152 2.68848 -6 6 -6h404zM416 108v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 204v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12
|
|
||||||
v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 300v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM164 288c0 -19.8818 -16.1182 -36 -36 -36
|
|
||||||
s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 192c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 96c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36z" />
|
|
||||||
<glyph glyph-name="flag" unicode=""
|
|
||||||
d="M336.174 368c35.4668 0 73.0195 12.6914 108.922 28.1797c31.6406 13.6514 66.9043 -9.65723 66.9043 -44.1162v-239.919c0 -16.1953 -8.1543 -31.3057 -21.7129 -40.1631c-26.5762 -17.3643 -70.0693 -39.9814 -128.548 -39.9814c-68.6084 0 -112.781 32 -161.913 32
|
|
||||||
c-56.5674 0 -89.957 -11.2803 -127.826 -28.5566v-83.4434c0 -8.83691 -7.16309 -16 -16 -16h-16c-8.83691 0 -16 7.16309 -16 16v406.438c-14.3428 8.2998 -24 23.7979 -24 41.5615c0 27.5693 23.2422 49.71 51.2012 47.8965
|
|
||||||
c22.9658 -1.49023 41.8662 -19.4717 44.4805 -42.3379c0.177734 -1.52441 0.321289 -4.00781 0.321289 -5.54199c0 -4.30176 -1.10352 -11.1035 -2.46289 -15.1846c22.418 8.68555 49.4199 15.168 80.7207 15.168c68.6084 0 112.781 -32 161.913 -32zM464 112v240
|
|
||||||
c-31.5059 -14.6338 -84.5547 -32 -127.826 -32c-59.9111 0 -101.968 32 -161.913 32c-41.4365 0 -80.4766 -16.5879 -102.261 -32v-232c31.4473 14.5967 84.4648 24 127.826 24c59.9111 0 101.968 -32 161.913 -32c41.4365 0 80.4775 16.5879 102.261 32z" />
|
|
||||||
<glyph glyph-name="bookmark" unicode="" horiz-adv-x="384"
|
|
||||||
d="M336 448c26.5098 0 48 -21.4902 48 -48v-464l-192 112l-192 -112v464c0 26.5098 21.4902 48 48 48h288zM336 19.5703v374.434c0 3.31348 -2.68555 5.99609 -6 5.99609h-276c-3.31152 0 -6 -2.68848 -6 -6v-374.43l144 84z" />
|
|
||||||
<glyph glyph-name="image" unicode=""
|
|
||||||
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM458 48c3.31152 0 6 2.68848 6 6v276c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-276
|
|
||||||
c0 -3.31152 2.68848 -6 6 -6h404zM128 296c22.0908 0 40 -17.9092 40 -40s-17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40zM96 96v48l39.5137 39.5146c4.6875 4.68652 12.2852 4.68652 16.9717 0l39.5146 -39.5146l119.514 119.515
|
|
||||||
c4.6875 4.68652 12.2852 4.68652 16.9717 0l87.5146 -87.5146v-80h-320z" />
|
|
||||||
<glyph glyph-name="edit" unicode="" horiz-adv-x="576"
|
|
||||||
d="M402.3 103.1l32 32c5 5 13.7002 1.5 13.7002 -5.69922v-145.4c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h273.5c7.09961 0 10.7002 -8.59961 5.7002 -13.7002l-32 -32c-1.5 -1.5 -3.5 -2.2998 -5.7002 -2.2998h-241.5v-352h352
|
|
||||||
v113.5c0 2.09961 0.799805 4.09961 2.2998 5.59961zM558.9 304.9l-262.601 -262.601l-90.3994 -10c-26.2002 -2.89941 -48.5 19.2002 -45.6006 45.6006l10 90.3994l262.601 262.601c22.8994 22.8994 59.8994 22.8994 82.6992 0l43.2002 -43.2002
|
|
||||||
c22.9004 -22.9004 22.9004 -60 0.100586 -82.7998zM460.1 274l-58.0996 58.0996l-185.8 -185.899l-7.2998 -65.2998l65.2998 7.2998zM524.9 353.7l-43.2002 43.2002c-4.10059 4.09961 -10.7998 4.09961 -14.7998 0l-30.9004 -30.9004l58.0996 -58.0996l30.9004 30.8994
|
|
||||||
c4 4.2002 4 10.7998 -0.0996094 14.9004z" />
|
|
||||||
<glyph glyph-name="times-circle" unicode=""
|
|
||||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM357.8 254.2l-62.2002 -62.2002l62.2002 -62.2002
|
|
||||||
c4.7002 -4.7002 4.7002 -12.2998 0 -17l-22.5996 -22.5996c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-62.2002 62.2002l-62.2002 -62.2002c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-22.5996 22.5996c-4.7002 4.7002 -4.7002 12.2998 0 17l62.2002 62.2002l-62.2002 62.2002
|
|
||||||
c-4.7002 4.7002 -4.7002 12.2998 0 17l22.5996 22.5996c4.7002 4.7002 12.2998 4.7002 17 0l62.2002 -62.2002l62.2002 62.2002c4.7002 4.7002 12.2998 4.7002 17 0l22.5996 -22.5996c4.7002 -4.7002 4.7002 -12.2998 0 -17z" />
|
|
||||||
<glyph glyph-name="check-circle" unicode=""
|
|
||||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200z
|
|
||||||
M396.204 261.733c4.66699 -4.70508 4.63672 -12.3037 -0.0673828 -16.9717l-172.589 -171.204c-4.70508 -4.66797 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66797 4.70605 -4.63672 12.3047 0.0683594 16.9717l22.7188 22.5361
|
|
||||||
c4.70508 4.66699 12.3027 4.63574 16.9697 -0.0693359l59.792 -60.2773l141.353 140.216c4.70508 4.66797 12.3027 4.6377 16.9697 -0.0673828z" />
|
|
||||||
<glyph glyph-name="question-circle" unicode=""
|
|
||||||
d="M256 440c136.957 0 248 -111.083 248 -248c0 -136.997 -111.043 -248 -248 -248s-248 111.003 -248 248c0 136.917 111.043 248 248 248zM256 -8c110.569 0 200 89.4697 200 200c0 110.529 -89.5088 200 -200 200c-110.528 0 -200 -89.5049 -200 -200
|
|
||||||
c0 -110.569 89.4678 -200 200 -200zM363.244 247.2c0 -67.0518 -72.4209 -68.084 -72.4209 -92.8633v-6.33691c0 -6.62695 -5.37305 -12 -12 -12h-45.6475c-6.62695 0 -12 5.37305 -12 12v8.65918c0 35.7451 27.1006 50.0342 47.5791 61.5156
|
|
||||||
c17.5615 9.84473 28.3242 16.541 28.3242 29.5791c0 17.2461 -21.999 28.6934 -39.7842 28.6934c-23.1885 0 -33.8936 -10.9775 -48.9424 -29.9697c-4.05664 -5.11914 -11.46 -6.07031 -16.666 -2.12402l-27.8232 21.0986
|
|
||||||
c-5.10742 3.87207 -6.25098 11.0654 -2.64453 16.3633c23.627 34.6934 53.7217 54.1846 100.575 54.1846c49.0713 0 101.45 -38.3037 101.45 -88.7998zM298 80c0 -23.1592 -18.8408 -42 -42 -42s-42 18.8408 -42 42s18.8408 42 42 42s42 -18.8408 42 -42z" />
|
|
||||||
<glyph glyph-name="eye" unicode="" horiz-adv-x="576"
|
|
||||||
d="M288 304c0.0927734 0 0.244141 0.000976562 0.336914 0.000976562c61.6641 0 111.71 -50.0469 111.71 -111.711c0 -61.6631 -50.0459 -111.71 -111.71 -111.71s-111.71 50.0469 -111.71 111.71c0 8.71289 1.95898 22.5781 4.37305 30.9502
|
|
||||||
c6.93066 -3.94141 19.0273 -7.18457 27 -7.24023c30.9121 0 56 25.0879 56 56c-0.0556641 7.97266 -3.29883 20.0693 -7.24023 27c8.42383 2.62207 22.4189 4.8623 31.2402 5zM572.52 206.6c1.9209 -3.79883 3.47949 -10.3379 3.47949 -14.5947
|
|
||||||
s-1.55859 -10.7959 -3.47949 -14.5947c-54.1992 -105.771 -161.59 -177.41 -284.52 -177.41s-230.29 71.5898 -284.52 177.4c-1.9209 3.79883 -3.47949 10.3379 -3.47949 14.5947s1.55859 10.7959 3.47949 14.5947c54.1992 105.771 161.59 177.41 284.52 177.41
|
|
||||||
s230.29 -71.5898 284.52 -177.4zM288 48c98.6602 0 189.1 55 237.93 144c-48.8398 89 -139.27 144 -237.93 144s-189.09 -55 -237.93 -144c48.8398 -89 139.279 -144 237.93 -144z" />
|
|
||||||
<glyph glyph-name="eye-slash" unicode="" horiz-adv-x="640"
|
|
||||||
d="M634 -23c3.31738 -2.65137 6.00977 -8.25098 6.00977 -12.498c0 -3.10449 -1.57715 -7.58984 -3.51953 -10.0117l-10 -12.4902c-2.65234 -3.31152 -8.24707 -6 -12.4902 -6c-3.09961 0 -7.58008 1.57227 -10 3.50977l-598 467.49
|
|
||||||
c-3.31738 2.65137 -6.00977 8.25098 -6.00977 12.498c0 3.10449 1.57715 7.58984 3.51953 10.0117l10 12.4902c2.65234 3.31152 8.24707 6 12.4902 6c3.09961 0 7.58008 -1.57227 10 -3.50977zM296.79 301.53c6.33496 1.35059 16.7324 2.45801 23.21 2.46973
|
|
||||||
c60.4805 0 109.36 -47.9102 111.58 -107.85zM343.21 82.46c-6.33496 -1.34375 -16.7334 -2.44629 -23.21 -2.45996c-60.4697 0 -109.35 47.9102 -111.58 107.84zM320 336c-19.8799 0 -39.2803 -2.7998 -58.2197 -7.09961l-46.4102 36.29
|
|
||||||
c32.9199 11.8096 67.9297 18.8096 104.63 18.8096c122.93 0 230.29 -71.5898 284.57 -177.4c1.91992 -3.79883 3.47949 -10.3379 3.47949 -14.5947s-1.55957 -10.7959 -3.47949 -14.5947c-11.7197 -22.7598 -35.4189 -56.4092 -52.9004 -75.1104l-37.7402 29.5
|
|
||||||
c14.333 15.0156 34.0449 41.9854 44 60.2002c-48.8398 89 -139.279 144 -237.93 144zM320 48c19.8896 0 39.2803 2.7998 58.2197 7.08984l46.4102 -36.2803c-32.9199 -11.7598 -67.9297 -18.8096 -104.63 -18.8096c-122.92 0 -230.28 71.5898 -284.51 177.4
|
|
||||||
c-1.9209 3.79883 -3.47949 10.3379 -3.47949 14.5947s1.55859 10.7959 3.47949 14.5947c11.7168 22.7568 35.4111 56.4014 52.8896 75.1006l37.7402 -29.5c-14.3467 -15.0107 -34.0811 -41.9756 -44.0498 -60.1904c48.8496 -89 139.279 -144 237.93 -144z" />
|
|
||||||
<glyph glyph-name="calendar-alt" unicode="" horiz-adv-x="448"
|
|
||||||
d="M148 160h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM256 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
|
||||||
c6.59961 0 12 -5.40039 12 -12v-40zM352 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM256 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40
|
|
||||||
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM160 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM352 76c0 -6.59961 -5.40039 -12 -12 -12h-40
|
|
||||||
c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40
|
|
||||||
c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="comment" unicode=""
|
|
||||||
d="M256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5c-3.80078 8.7998 -2 19 4.59961 26
|
|
||||||
c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004
|
|
||||||
l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
|
|
||||||
<glyph glyph-name="folder" unicode=""
|
|
||||||
d="M464 320c26.5098 0 48 -21.4902 48 -48v-224c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h146.74c8.49023 0 16.6299 -3.37012 22.6299 -9.37012l54.6299 -54.6299h192zM464 48v224h-198.62
|
|
||||||
c-8.49023 0 -16.6299 3.37012 -22.6299 9.37012l-54.6299 54.6299h-140.12v-288h416z" />
|
|
||||||
<glyph glyph-name="folder-open" unicode="" horiz-adv-x="576"
|
|
||||||
d="M527.9 224c37.6992 0 60.6992 -41.5 40.6992 -73.4004l-79.8994 -128c-8.7998 -14.0996 -24.2002 -22.5996 -40.7002 -22.5996h-400c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h160l64 -64h160c26.5 0 48 -21.5 48 -48v-48h47.9004zM48 330v-233.4l62.9004 104.2
|
|
||||||
c8.69922 14.4004 24.2998 23.2002 41.0996 23.2002h280v42c0 3.2998 -2.7002 6 -6 6h-173.9l-64 64h-134.1c-3.2998 0 -6 -2.7002 -6 -6zM448 48l80 128h-378.8l-77.2002 -128h376z" />
|
|
||||||
<glyph glyph-name="chart-bar" unicode=""
|
|
||||||
d="M396.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v230.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-230.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM204.8 96
|
|
||||||
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v198.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-198.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM300.8 96
|
|
||||||
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v134.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-134.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM496 48c8.83984 0 16 -7.16016 16 -16v-16
|
|
||||||
c0 -8.83984 -7.16016 -16 -16 -16h-464c-17.6699 0 -32 14.3301 -32 32v336c0 8.83984 7.16016 16 16 16h16c8.83984 0 16 -7.16016 16 -16v-320h448zM108.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v70.4004c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004
|
|
||||||
c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-70.4004c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004z" />
|
|
||||||
<glyph glyph-name="comments" unicode="" horiz-adv-x="576"
|
|
||||||
d="M532 61.7998c15.2998 -30.7002 37.4004 -54.5 37.7998 -54.7998c6.2998 -6.7002 8 -16.5 4.40039 -25c-3.7002 -8.5 -12 -14 -21.2002 -14c-53.5996 0 -96.7002 20.2998 -125.2 38.7998c-19 -4.39941 -39 -6.7998 -59.7998 -6.7998
|
|
||||||
c-86.2002 0 -159.9 40.4004 -191.3 97.7998c-9.7002 1.2002 -19.2002 2.7998 -28.4004 4.90039c-28.5 -18.6006 -71.7002 -38.7998 -125.2 -38.7998c-9.19922 0 -17.5996 5.5 -21.1992 14c-3.7002 8.5 -1.90039 18.2998 4.39941 25
|
|
||||||
c0.400391 0.399414 22.4004 24.1992 37.7002 54.8994c-27.5 27.2002 -44 61.2002 -44 98.2002c0 88.4004 93.0996 160 208 160c86.2998 0 160.3 -40.5 191.8 -98.0996c99.7002 -11.8008 176.2 -77.9004 176.2 -157.9c0 -37.0996 -16.5 -71.0996 -44 -98.2002zM139.2 154.1
|
|
||||||
l19.7998 -4.5c16 -3.69922 32.5 -5.59961 49 -5.59961c86.7002 0 160 51.2998 160 112s-73.2998 112 -160 112s-160 -51.2998 -160 -112c0 -28.7002 16.2002 -50.5996 29.7002 -64l24.7998 -24.5l-15.5 -31.0996c-2.59961 -5.10059 -5.2998 -10.1006 -8 -14.8008
|
|
||||||
c14.5996 5.10059 29 12.3008 43.0996 21.4004zM498.3 96c13.5 13.4004 29.7002 35.2998 29.7002 64c0 49.2002 -48.2998 91.5 -112.7 106c0.299805 -3.2998 0.700195 -6.59961 0.700195 -10c0 -80.9004 -78 -147.5 -179.3 -158.3
|
|
||||||
c29.0996 -29.6006 77.2998 -49.7002 131.3 -49.7002c16.5 0 33 1.90039 49 5.59961l19.9004 4.60059l17.0996 -11.1006c14.0996 -9.09961 28.5 -16.2998 43.0996 -21.3994c-2.69922 4.7002 -5.39941 9.7002 -8 14.7998l-15.5 31.0996z" />
|
|
||||||
<glyph glyph-name="star-half" unicode="" horiz-adv-x="576"
|
|
||||||
d="M288 62.7002v-54.2998l-130.7 -68.6006c-23.3994 -12.2998 -50.8994 7.60059 -46.3994 33.7002l25 145.5l-105.7 103c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2002l65.2998 132.4c5.90039 11.8994 17.2998 17.7998 28.7002 17.7998v-68.0996l-62.2002 -126
|
|
||||||
l-139 -20.2002l100.601 -98l-23.7002 -138.4z" />
|
|
||||||
<glyph glyph-name="lemon" unicode=""
|
|
||||||
d="M484.112 420.111c28.1221 -28.123 35.9434 -68.0039 19.0215 -97.0547c-23.0576 -39.584 50.1436 -163.384 -82.3311 -295.86c-132.301 -132.298 -256.435 -59.3594 -295.857 -82.3291c-29.0459 -16.917 -68.9219 -9.11426 -97.0576 19.0205
|
|
||||||
c-28.1221 28.1221 -35.9434 68.0029 -19.0215 97.0547c23.0566 39.5859 -50.1436 163.386 82.3301 295.86c132.308 132.309 256.407 59.3496 295.862 82.332c29.0498 16.9219 68.9307 9.09863 97.0537 -19.0234zM461.707 347.217
|
|
||||||
c13.5166 23.2031 -27.7578 63.7314 -50.4883 50.4912c-66.6025 -38.7939 -165.646 45.5898 -286.081 -74.8457c-120.444 -120.445 -36.0449 -219.472 -74.8447 -286.08c-13.542 -23.2471 27.8145 -63.6953 50.4932 -50.4883
|
|
||||||
c66.6006 38.7949 165.636 -45.5996 286.076 74.8428c120.444 120.445 36.0449 219.472 74.8447 286.08zM291.846 338.481c1.37012 -10.96 -6.40332 -20.957 -17.3643 -22.3271c-54.8467 -6.85547 -135.779 -87.7871 -142.636 -142.636
|
|
||||||
c-1.37305 -10.9883 -11.3984 -18.7334 -22.3262 -17.3643c-10.9609 1.37012 -18.7344 11.3652 -17.3643 22.3262c9.16211 73.2852 104.167 168.215 177.364 177.364c10.9531 1.36816 20.9561 -6.40234 22.3262 -17.3633z" />
|
|
||||||
<glyph glyph-name="credit-card" unicode="" horiz-adv-x="576"
|
|
||||||
d="M527.9 416c26.5996 0 48.0996 -21.5 48.0996 -48v-352c0 -26.5 -21.5 -48 -48.0996 -48h-479.801c-26.5996 0 -48.0996 21.5 -48.0996 48v352c0 26.5 21.5 48 48.0996 48h479.801zM54.0996 368c-3.2998 0 -6 -2.7002 -6 -6v-42h479.801v42c0 3.2998 -2.7002 6 -6 6
|
|
||||||
h-467.801zM521.9 16c3.2998 0 6 2.7002 6 6v170h-479.801v-170c0 -3.2998 2.7002 -6 6 -6h467.801zM192 116v-40c0 -6.59961 -5.40039 -12 -12 -12h-72c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h72c6.59961 0 12 -5.40039 12 -12zM384 116v-40
|
|
||||||
c0 -6.59961 -5.40039 -12 -12 -12h-136c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h136c6.59961 0 12 -5.40039 12 -12z" />
|
|
||||||
<glyph glyph-name="hdd" unicode="" horiz-adv-x="576"
|
|
||||||
d="M567.403 212.358c5.59668 -8.04688 8.59668 -17.6113 8.59668 -27.4121v-136.946c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v136.946c0 8.30957 3.85156 20.5898 8.59668 27.4121l105.08 151.053
|
|
||||||
c7.90625 11.3652 25.5596 20.5889 39.4033 20.5889h0.000976562h269.838h0.000976562c13.8438 0 31.4971 -9.22363 39.4033 -20.5889zM153.081 336l-77.9131 -112h425.664l-77.9131 112h-269.838zM528 48v128h-480v-128h480zM496 112c0 -17.6729 -14.3271 -32 -32 -32
|
|
||||||
s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32zM400 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32z" />
|
|
||||||
<glyph glyph-name="hand-point-right" unicode=""
|
|
||||||
d="M428.8 310.4c45.0996 0 83.2002 -38.1016 83.2002 -83.2002c0 -45.6162 -37.7646 -83.2002 -83.2002 -83.2002h-35.6475c-1.41602 -6.36719 -4.96875 -16.252 -7.92969 -22.0645c2.50586 -22.0059 -3.50293 -44.9775 -15.9844 -62.791
|
|
||||||
c-1.14062 -52.4863 -37.3984 -91.1445 -99.9404 -91.1445h-21.2988c-60.0635 0 -98.5117 40 -127.2 40h-2.67871c-5.74707 -4.95215 -13.5361 -8 -22.1201 -8h-64c-17.6729 0 -32 12.8936 -32 28.7998v230.4c0 15.9062 14.3271 28.7998 32 28.7998h64.001
|
|
||||||
c8.58398 0 16.373 -3.04785 22.1201 -8h2.67871c6.96387 0 14.8623 6.19336 30.1816 23.6689l0.128906 0.148438l0.130859 0.145508c8.85645 9.93652 18.1162 20.8398 25.8506 33.2529c18.7051 30.2471 30.3936 78.7842 75.707 78.7842c56.9277 0 92 -35.2861 92 -83.2002
|
|
||||||
v-0.0839844c0 -6.21777 -0.974609 -16.2148 -2.17578 -22.3154h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994c0 26.4004 -20.625 35.2002 -44 35.2002
|
|
||||||
c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
|
|
||||||
c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
|
||||||
<glyph glyph-name="hand-point-left" unicode=""
|
|
||||||
d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529
|
|
||||||
l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64
|
|
||||||
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-2.96094 5.8125 -6.51367 15.6973 -7.92969 22.0645h-35.6465
|
|
||||||
c-45.4355 0 -83.2002 37.584 -83.2002 83.2002zM48 227.2c0 -18.9756 16.2246 -35.2002 35.2002 -35.2002h91.0244c-12.8369 -14.6689 -14.415 -42.8252 4.9502 -61.0498c-11.2256 -19.6465 -1.68652 -45.624 12.9248 -53.625
|
|
||||||
c-6.52246 -39.1279 10.0771 -61.3252 50.6016 -61.3252h21.2988c45.4912 0 77.21 35.9131 120 39.6768v176.752c-25.2393 2.96289 -42.9658 21.2227 -59.0752 39.5967c-11.2744 12.6494 -21.7246 25.2998 -30.7988 39.875
|
|
||||||
c-14.4814 23.3877 -26.1318 56.0996 -34.9258 56.0996c-23.375 0 -44 -8.7998 -44 -35.2002c0 -35.2002 26.3994 -53.0752 26.3994 -70.3994h-158.399c-18.4248 0 -35.2002 -16.5 -35.2002 -35.2002zM448 88c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24
|
|
||||||
s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
|
||||||
<glyph glyph-name="hand-point-up" unicode="" horiz-adv-x="448"
|
|
||||||
d="M105.6 364.8c0 45.0996 38.1016 83.2002 83.2002 83.2002c45.6162 0 83.2002 -37.7646 83.2002 -83.2002v-35.6465c6.36719 -1.41602 16.252 -4.96875 22.0645 -7.92969c22.0059 2.50684 44.9775 -3.50293 62.791 -15.9844
|
|
||||||
c52.4863 -1.14062 91.1445 -37.3984 91.1445 -99.9404v-21.2988c0 -60.0635 -40 -98.5117 -40 -127.2v-2.67871c4.95215 -5.74707 8 -13.5361 8 -22.1201v-64c0 -17.6729 -12.8936 -32 -28.7998 -32h-230.4c-15.9062 0 -28.7998 14.3271 -28.7998 32v64
|
|
||||||
c0 8.58398 3.04785 16.373 8 22.1201v2.67871c0 6.96387 -6.19336 14.8623 -23.6689 30.1816l-0.148438 0.128906l-0.145508 0.130859c-9.93652 8.85645 -20.8398 18.1162 -33.2529 25.8506c-30.2471 18.7051 -78.7842 30.3936 -78.7842 75.707
|
|
||||||
c0 56.9277 35.2861 92 83.2002 92h0.0839844c6.21777 0 16.2148 -0.974609 22.3154 -2.17578v86.1768zM224 364.8c0 18.9756 -16.2246 35.2002 -35.2002 35.2002c-18.7002 0 -35.2002 -16.7754 -35.2002 -35.2002v-158.399c-17.3242 0 -35.1992 26.3994 -70.3994 26.3994
|
|
||||||
c-26.4004 0 -35.2002 -20.625 -35.2002 -44c0 -8.79395 32.7119 -20.4443 56.0996 -34.9258c14.5752 -9.07422 27.2256 -19.5244 39.875 -30.7988c18.374 -16.1094 36.6328 -33.8359 39.5967 -59.0752h176.753c3.7627 42.79 39.6758 74.5088 39.6758 120v21.2988
|
|
||||||
c0 40.5244 -22.1973 57.124 -61.3252 50.6006c-8.00098 14.6113 -33.9785 24.1514 -53.625 12.9248c-18.2246 19.3652 -46.3809 17.7871 -61.0498 4.9502v91.0254zM352 24c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
|
||||||
<glyph glyph-name="hand-point-down" unicode="" horiz-adv-x="448"
|
|
||||||
d="M188.8 -64c-45.0986 0 -83.2002 38.1006 -83.2002 83.2002v86.1758c-6.91016 -1.3623 -14.374 -2.17578 -22.3994 -2.17578c-47.9141 0 -83.2002 35.0723 -83.2002 92c0 45.3135 48.5371 57.002 78.7852 75.707c12.4121 7.73438 23.3154 16.9951 33.2529 25.8506
|
|
||||||
l0.145508 0.130859l0.148438 0.128906c17.4746 15.3213 23.668 23.2197 23.668 30.1836v2.67871c-4.95215 5.74707 -8 13.5361 -8 22.1201v64c0 17.6729 12.8936 32 28.7998 32h230.4c15.9062 0 28.7998 -14.3271 28.7998 -32v-64.001
|
|
||||||
c0 -8.58398 -3.04785 -16.373 -8 -22.1201v-2.67871c0 -28.6885 40 -67.1367 40 -127.2v-21.2988c0 -62.542 -38.6582 -98.8008 -91.1445 -99.9404c-17.8135 -12.4814 -40.7852 -18.4922 -62.791 -15.9844c-5.8125 -2.96094 -15.6973 -6.51367 -22.0645 -7.92969v-35.6465
|
|
||||||
c0 -45.4355 -37.584 -83.2002 -83.2002 -83.2002zM188.8 -16c18.9756 0 35.2002 16.2246 35.2002 35.2002v91.0244c14.6689 -12.8369 42.8252 -14.415 61.0498 4.9502c19.6465 -11.2256 45.624 -1.68652 53.625 12.9248c39.1279 -6.52246 61.3252 10.0771 61.3252 50.6016
|
|
||||||
v21.2988c0 45.4912 -35.9131 77.21 -39.6768 120h-176.752c-2.96289 -25.2393 -21.2227 -42.9658 -39.5967 -59.0752c-12.6494 -11.2744 -25.2998 -21.7246 -39.875 -30.7988c-23.3877 -14.4814 -56.0996 -26.1318 -56.0996 -34.9258c0 -23.375 8.7998 -44 35.2002 -44
|
|
||||||
c35.2002 0 53.0752 26.3994 70.3994 26.3994v-158.399c0 -18.4248 16.5 -35.2002 35.2002 -35.2002zM328 384c0 -13.2549 10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24z" />
|
|
||||||
<glyph glyph-name="copy" unicode="" horiz-adv-x="448"
|
|
||||||
d="M433.941 382.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-80v-48c0 -26.5098 -21.4902 -48 -48 -48h-224c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h80v48c0 26.5098 21.4902 48 48 48
|
|
||||||
h172.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM266 -16c3.31152 0 6 2.68848 6 6v42h-96c-26.5098 0 -48 21.4902 -48 48v224h-74c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM394 80c3.31152 0 6 2.68848 6 6v202h-88
|
|
||||||
c-13.2549 0 -24 10.7451 -24 24v88h-106c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM400 336v9.63184v0.000976562c0 1.37207 -0.787109 3.27246 -1.75684 4.24219l-48.3682 48.3682c-1.12598 1.125 -2.65234 1.75684 -4.24316 1.75684h-9.63184
|
|
||||||
v-64h64z" />
|
|
||||||
<glyph glyph-name="save" unicode="" horiz-adv-x="448"
|
|
||||||
d="M433.941 318.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h268.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM272 368h-128v-80h128v80
|
|
||||||
zM394 16c3.31152 0 6 2.68848 6 6v259.632v0.000976562c0 1.37207 -0.787109 3.27246 -1.75684 4.24219l-78.2432 78.2432v-100.118c0 -13.2549 -10.7451 -24 -24 -24h-176c-13.2549 0 -24 10.7451 -24 24v104h-42c-3.31152 0 -6 -2.68848 -6 -6v-340
|
|
||||||
c0 -3.31152 2.68848 -6 6 -6h340zM224 216c48.5234 0 88 -39.4766 88 -88s-39.4766 -88 -88 -88s-88 39.4766 -88 88s39.4766 88 88 88zM224 88c22.0557 0 40 17.9443 40 40s-17.9443 40 -40 40s-40 -17.9443 -40 -40s17.9443 -40 40 -40z" />
|
|
||||||
<glyph glyph-name="square" unicode="" horiz-adv-x="448"
|
|
||||||
d="M400 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352zM394 16c3.2998 0 6 2.7002 6 6v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340z" />
|
|
||||||
<glyph glyph-name="envelope" unicode=""
|
|
||||||
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM464 336h-416v-40.8047c22.4248 -18.2627 58.1797 -46.6602 134.587 -106.49
|
|
||||||
c16.834 -13.2422 50.2051 -45.0762 73.4131 -44.7012c23.2119 -0.371094 56.5723 31.4541 73.4131 44.7012c76.4189 59.8389 112.165 88.2305 134.587 106.49v40.8047zM48 48h416v185.601c-22.915 -18.252 -55.4189 -43.8691 -104.947 -82.6523
|
|
||||||
c-22.5439 -17.748 -60.3359 -55.1787 -103.053 -54.9473c-42.9277 -0.231445 -81.2051 37.75 -103.062 54.9551c-49.5293 38.7842 -82.0244 64.3945 -104.938 82.6455v-185.602z" />
|
|
||||||
<glyph glyph-name="lightbulb" unicode="" horiz-adv-x="352"
|
|
||||||
d="M176 368c8.83984 0 16 -7.16016 16 -16s-7.16016 -16 -16 -16c-35.2803 0 -64 -28.7002 -64 -64c0 -8.83984 -7.16016 -16 -16 -16s-16 7.16016 -16 16c0 52.9404 43.0596 96 96 96zM96.0596 -11.1699l-0.0400391 43.1797h159.961l-0.0507812 -43.1797
|
|
||||||
c-0.00976562 -3.13965 -0.939453 -6.21973 -2.67969 -8.83984l-24.5098 -36.8398c-2.95996 -4.45996 -7.95996 -7.14062 -13.3203 -7.14062h-78.8496c-5.35059 0 -10.3506 2.68066 -13.3203 7.14062l-24.5098 36.8398c-1.75 2.62012 -2.68066 5.68945 -2.68066 8.83984z
|
|
||||||
M176 448c97.2002 0 176 -78.7998 176 -176c0 -44.3701 -16.4502 -84.8496 -43.5498 -115.79c-16.6406 -18.9795 -42.7402 -58.79 -52.4199 -92.1602v-0.0498047h-48v0.0996094c0.00390625 4.04199 0.999023 10.4482 2.21973 14.3008
|
|
||||||
c5.67969 17.9893 22.9902 64.8496 62.0996 109.46c20.4102 23.29 31.6504 53.1699 31.6504 84.1396c0 70.5801 -57.4199 128 -128 128c-68.2803 0 -128.15 -54.3604 -127.95 -128c0.0898438 -30.9902 11.0703 -60.71 31.6104 -84.1396
|
|
||||||
c39.3496 -44.9004 56.5801 -91.8604 62.1699 -109.67c1.42969 -4.56055 2.13965 -9.30078 2.15039 -14.0703v-0.120117h-48v0.0595703c-9.68066 33.3604 -35.7803 73.1709 -52.4209 92.1602c-27.1094 30.9307 -43.5596 71.4102 -43.5596 115.78
|
|
||||||
c0 93.0303 73.7197 176 176 176z" />
|
|
||||||
<glyph glyph-name="bell" unicode="" horiz-adv-x="448"
|
|
||||||
d="M439.39 85.71c6 -6.44043 8.66016 -14.1602 8.61035 -21.71c-0.0996094 -16.4004 -12.9805 -32 -32.0996 -32h-383.801c-19.1191 0 -31.9893 15.5996 -32.0996 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c19.3193 20.7598 55.4697 51.9902 55.4697 154.29
|
|
||||||
c0 77.7002 54.4795 139.9 127.939 155.16v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -102.3 36.1504 -133.53 55.4697 -154.29zM67.5303 80h312.939
|
|
||||||
c-21.2197 27.96 -44.4199 74.3203 -44.5293 159.42c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112s-112 -50.1396 -112 -112c0 -0.200195 0.0595703 -0.379883 0.0595703 -0.580078
|
|
||||||
c-0.109375 -85.0898 -23.3096 -131.45 -44.5293 -159.42zM224 -64c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
|
||||||
<glyph glyph-name="hospital" unicode="" horiz-adv-x="448"
|
|
||||||
d="M128 204v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12zM268 192c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40
|
|
||||||
c0 -6.62695 -5.37305 -12 -12 -12h-40zM192 108c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40zM268 96c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40
|
|
||||||
c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.62695 5.37305 12 12 12h19.5v378.965c0 11.6172 10.7451 21.0352 24 21.0352h88.5v40c0 13.2549 10.7451 24 24 24h112c13.2549 0 24 -10.7451 24 -24v-40h88.5
|
|
||||||
c13.2549 0 24 -9.41797 24 -21.0352v-378.965h19.5c6.62695 0 12 -5.37305 12 -12zM79.5 -15h112.5v67c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-67h112.5v351h-64.5v-24c0 -13.2549 -10.7451 -24 -24 -24h-112c-13.2549 0 -24 10.7451 -24 24v24
|
|
||||||
h-64.5v-351zM266 384h-26v26c0 3.31152 -2.68848 6 -6 6h-20c-3.31152 0 -6 -2.68848 -6 -6v-26h-26c-3.31152 0 -6 -2.68848 -6 -6v-20c0 -3.31152 2.68848 -6 6 -6h26v-26c0 -3.31152 2.68848 -6 6 -6h20c3.31152 0 6 2.68848 6 6v26h26c3.31152 0 6 2.68848 6 6v20
|
|
||||||
c0 3.31152 -2.68848 6 -6 6z" />
|
|
||||||
<glyph glyph-name="plus-square" unicode="" horiz-adv-x="448"
|
|
||||||
d="M352 208v-32c0 -6.59961 -5.40039 -12 -12 -12h-88v-88c0 -6.59961 -5.40039 -12 -12 -12h-32c-6.59961 0 -12 5.40039 -12 12v88h-88c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h88v88c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12
|
|
||||||
v-88h88c6.59961 0 12 -5.40039 12 -12zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340
|
|
||||||
c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="circle" unicode=""
|
|
||||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200z" />
|
|
||||||
<glyph glyph-name="smile" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
|
||||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM332 135.4c8.5 10.1992 23.7002 11.5 33.7998 3.09961c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998
|
|
||||||
c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.0996 8.40039 25.2998 7.09961 33.7998 -3.09961c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004z" />
|
|
||||||
<glyph glyph-name="frown" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
|
||||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 144c40.2002 0 78 -17.7002 103.8 -48.5996c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008
|
|
||||||
c-10.7002 -8.7998 -25.7002 -6.59961 -33.7998 3.10059c-16.6006 20 -41 31.3994 -66.9004 31.3994s-50.2998 -11.5 -66.9004 -31.3994c-8.5 -10.2002 -23.5996 -11.5 -33.7998 -3.10059c-10.2002 8.5 -11.5996 23.6006 -3.09961 33.8008
|
|
||||||
c25.7998 30.8994 63.5996 48.5996 103.8 48.5996z" />
|
|
||||||
<glyph glyph-name="meh" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
|
||||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM336 128c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-176c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h176z
|
|
||||||
" />
|
|
||||||
<glyph glyph-name="keyboard" unicode="" horiz-adv-x="576"
|
|
||||||
d="M528 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h480zM536 48v288c0 4.41113 -3.58887 8 -8 8h-480c-4.41113 0 -8 -3.58887 -8 -8v-288c0 -4.41113 3.58887 -8 8 -8
|
|
||||||
h480c4.41113 0 8 3.58887 8 8zM170 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM266 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
|
|
||||||
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM362 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM458 178c0 -6.62695 -5.37305 -12 -12 -12h-28
|
|
||||||
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 96c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 96
|
|
||||||
c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28
|
|
||||||
c6.62695 0 12 -5.37305 12 -12v-28zM218 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM314 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
|
|
||||||
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM410 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 260c0 -6.62695 -5.37305 -12 -12 -12h-28
|
|
||||||
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM408 102c0 -6.62695 -5.37305 -12 -12 -12h-216c-6.62695 0 -12 5.37305 -12 12v16c0 6.62695 5.37305 12 12 12h216c6.62695 0 12 -5.37305 12 -12v-16z" />
|
|
||||||
<glyph glyph-name="calendar" unicode="" horiz-adv-x="448"
|
|
||||||
d="M400 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12
|
|
||||||
v-52h48zM394 -16c3.2998 0 6 2.7002 6 6v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340z" />
|
|
||||||
<glyph glyph-name="play-circle" unicode=""
|
|
||||||
d="M371.7 210c16.3994 -9.2002 16.3994 -32.9004 0 -42l-176 -101c-15.9004 -8.7998 -35.7002 2.59961 -35.7002 21v208c0 18.5 19.9004 29.7998 35.7002 21zM504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192
|
|
||||||
c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200z" />
|
|
||||||
<glyph glyph-name="minus-square" unicode="" horiz-adv-x="448"
|
|
||||||
d="M108 164c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h232c6.59961 0 12 -5.40039 12 -12v-32c0 -6.59961 -5.40039 -12 -12 -12h-232zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352
|
|
||||||
c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="check-square" unicode="" horiz-adv-x="448"
|
|
||||||
d="M400 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h352zM400 16v352h-352v-352h352zM364.136 257.724l-172.589 -171.204
|
|
||||||
c-4.70508 -4.66699 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66699 4.70508 -4.63672 12.3037 0.0693359 16.9717l22.7188 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l59.792 -60.2773l141.353 140.217
|
|
||||||
c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0683594l22.5361 -22.7178c4.66699 -4.70605 4.63672 -12.3047 -0.0683594 -16.9717z" />
|
|
||||||
<glyph glyph-name="share-square" unicode="" horiz-adv-x="576"
|
|
||||||
d="M561.938 289.94c18.75 -18.7402 18.75 -49.1406 0 -67.8809l-143.998 -144c-29.9727 -29.9727 -81.9404 -9.05273 -81.9404 33.9404v53.7998c-101.266 -7.83691 -99.625 -31.6406 -84.1104 -78.7598c14.2285 -43.0889 -33.4736 -79.248 -71.0195 -55.7402
|
|
||||||
c-51.6924 32.3057 -84.8701 83.0635 -84.8701 144.76c0 39.3408 12.2197 72.7402 36.3301 99.3008c19.8398 21.8398 47.7402 38.4697 82.9102 49.4199c36.7295 11.4395 78.3096 16.1094 120.76 17.9893v57.1982c0 42.9355 51.9258 63.9541 81.9404 33.9404zM384 112l144 144
|
|
||||||
l-144 144v-104.09c-110.86 -0.90332 -240 -10.5166 -240 -119.851c0 -52.1396 32.79 -85.6094 62.3096 -104.06c-39.8174 120.65 48.999 141.918 177.69 143.84v-103.84zM408.74 27.5068c6.14844 1.75684 15.5449 5.92383 20.9736 9.30273
|
|
||||||
c7.97656 4.95215 18.2861 -0.825195 18.2861 -10.2139v-42.5957c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h132c6.62695 0 12 -5.37305 12 -12v-4.48633c0 -4.91699 -2.9873 -9.36914 -7.56934 -11.1514
|
|
||||||
c-13.7021 -5.33105 -26.3955 -11.5371 -38.0498 -18.585c-1.59668 -0.974609 -4.41016 -1.77051 -6.28027 -1.77734h-86.1006c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340c3.31152 0 6 2.68848 6 6v25.9658c0 5.37012 3.5791 10.0596 8.74023 11.541
|
|
||||||
z" />
|
|
||||||
<glyph glyph-name="compass" unicode="" horiz-adv-x="496"
|
|
||||||
d="M347.94 318.14c16.6592 7.61035 33.8096 -9.54004 26.1992 -26.1992l-65.9697 -144.341c-2.73047 -5.97363 -9.7959 -13.0391 -15.7695 -15.7695l-144.341 -65.9697c-16.6592 -7.61035 -33.8096 9.5498 -26.1992 26.1992l65.9697 144.341
|
|
||||||
c2.73047 5.97363 9.7959 13.0391 15.7695 15.7695zM270.58 169.42c12.4697 12.4697 12.4697 32.6904 0 45.1602s-32.6904 12.4697 -45.1602 0s-12.4697 -32.6904 0 -45.1602s32.6904 -12.4697 45.1602 0zM248 440c136.97 0 248 -111.03 248 -248s-111.03 -248 -248 -248
|
|
||||||
s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
|
||||||
<glyph glyph-name="caret-square-down" unicode="" horiz-adv-x="448"
|
|
||||||
d="M125.1 240h197.801c10.6992 0 16.0996 -13 8.5 -20.5l-98.9004 -98.2998c-4.7002 -4.7002 -12.2002 -4.7002 -16.9004 0l-98.8994 98.2998c-7.7002 7.5 -2.2998 20.5 8.39941 20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
|
||||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="caret-square-up" unicode="" horiz-adv-x="448"
|
|
||||||
d="M322.9 144h-197.801c-10.6992 0 -16.0996 13 -8.5 20.5l98.9004 98.2998c4.7002 4.7002 12.2002 4.7002 16.9004 0l98.8994 -98.2998c7.7002 -7.5 2.2998 -20.5 -8.39941 -20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
|
||||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="caret-square-right" unicode="" horiz-adv-x="448"
|
|
||||||
d="M176 93.0996v197.801c0 10.6992 13 16.0996 20.5 8.5l98.2998 -98.9004c4.7002 -4.7002 4.7002 -12.2002 0 -16.9004l-98.2998 -98.8994c-7.5 -7.7002 -20.5 -2.2998 -20.5 8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
|
||||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="file" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
|
||||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416z" />
|
|
||||||
<glyph glyph-name="file-alt" unicode="" horiz-adv-x="384"
|
|
||||||
d="M288 200v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v28c0 6.59961 5.40039 12 12 12h168c6.59961 0 12 -5.40039 12 -12zM276 128c6.59961 0 12 -5.40039 12 -12v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12
|
|
||||||
v28c0 6.59961 5.40039 12 12 12h168zM384 316.1v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996l83.9004 -83.9004c9 -8.90039 14.0996 -21.2002 14.0996 -33.9004z
|
|
||||||
M256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288z" />
|
|
||||||
<glyph glyph-name="thumbs-up" unicode=""
|
|
||||||
d="M466.27 161.31c4.6748 -22.6465 0.864258 -44.5371 -8.98926 -62.9893c2.95898 -23.8682 -4.02148 -48.5654 -17.3398 -66.9902c-0.954102 -55.9072 -35.8232 -95.3301 -112.94 -95.3301c-7 0 -15 0.00976562 -22.2197 0.00976562
|
|
||||||
c-102.742 0 -133.293 38.9395 -177.803 39.9404c-3.56934 -13.7764 -16.085 -23.9502 -30.9775 -23.9502h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h98.7598c19.1455 16.9531 46.0137 60.6533 68.7598 83.4004
|
|
||||||
c13.667 13.667 10.1533 108.6 71.7607 108.6c57.5801 0 95.2695 -31.9355 95.2695 -104.73c0 -18.4092 -3.92969 -33.7295 -8.84961 -46.5391h36.4795c48.6025 0 85.8203 -41.5654 85.8203 -85.5801c0 -19.1504 -4.95996 -34.9902 -13.7305 -49.8408zM404.52 107.48
|
|
||||||
c21.5811 20.3838 18.6992 51.0645 5.21094 65.6191c9.44922 0 22.3594 18.9102 22.2695 37.8105c-0.0898438 18.9102 -16.71 37.8203 -37.8203 37.8203h-103.989c0 37.8193 28.3594 55.3691 28.3594 94.5391c0 23.75 0 56.7305 -47.2695 56.7305
|
|
||||||
c-18.9102 -18.9102 -9.45996 -66.1797 -37.8203 -94.54c-26.5596 -26.5703 -66.1797 -97.46 -94.54 -97.46h-10.9199v-186.17c53.6113 0 100.001 -37.8203 171.64 -37.8203h37.8203c35.5117 0 60.8203 17.1201 53.1201 65.9004
|
|
||||||
c15.2002 8.16016 26.5 36.4395 13.9395 57.5703zM88 16c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
|
||||||
<glyph glyph-name="thumbs-down" unicode=""
|
|
||||||
d="M466.27 222.69c8.77051 -14.8506 13.7305 -30.6904 13.7305 -49.8408c0 -44.0146 -37.2178 -85.5801 -85.8203 -85.5801h-36.4795c4.91992 -12.8096 8.84961 -28.1299 8.84961 -46.5391c0 -72.7949 -37.6895 -104.73 -95.2695 -104.73
|
|
||||||
c-61.6074 0 -58.0938 94.9326 -71.7607 108.6c-22.7461 22.7471 -49.6133 66.4473 -68.7598 83.4004h-7.05176c-5.5332 -9.56152 -15.8662 -16 -27.708 -16h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h64c8.11328 0 15.5146 -3.02539 21.1553 -8
|
|
||||||
h10.8447c40.9971 0 73.1953 39.9902 176.78 39.9902c7.21973 0 15.2197 0.00976562 22.2197 0.00976562c77.1172 0 111.986 -39.4229 112.94 -95.3301c13.3184 -18.4248 20.2979 -43.1221 17.3398 -66.9902c9.85352 -18.4521 13.6641 -40.3428 8.98926 -62.9893zM64 152
|
|
||||||
c13.2549 0 24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24zM394.18 135.27c21.1104 0 37.7305 18.9102 37.8203 37.8203c0.0898438 18.9004 -12.8203 37.8105 -22.2695 37.8105c13.4883 14.5547 16.3701 45.2354 -5.21094 65.6191
|
|
||||||
c12.5605 21.1309 1.26074 49.4102 -13.9395 57.5703c7.7002 48.7803 -17.6084 65.9004 -53.1201 65.9004h-37.8203c-71.6387 0 -118.028 -37.8203 -171.64 -37.8203v-186.17h10.9199c28.3604 0 67.9805 -70.8896 94.54 -97.46
|
|
||||||
c28.3604 -28.3604 18.9102 -75.6299 37.8203 -94.54c47.2695 0 47.2695 32.9805 47.2695 56.7305c0 39.1699 -28.3594 56.7197 -28.3594 94.5391h103.989z" />
|
|
||||||
<glyph glyph-name="sun" unicode=""
|
|
||||||
d="M494.2 226.1c11.2002 -7.59961 17.7998 -20.0996 17.8994 -33.6992c0 -13.4004 -6.69922 -26 -17.7998 -33.5l-59.7998 -40.5l13.7002 -71c2.5 -13.2002 -1.60059 -26.8008 -11.1006 -36.3008s-22.8994 -13.7998 -36.2998 -11.0996l-70.8994 13.7002l-40.4004 -59.9004
|
|
||||||
c-7.5 -11.0996 -20.0996 -17.7998 -33.5 -17.7998s-26 6.7002 -33.5 17.9004l-40.4004 59.8994l-70.7998 -13.7002c-13.3994 -2.59961 -26.7998 1.60059 -36.2998 11.1006s-13.7002 23.0996 -11.0996 36.2998l13.6992 71l-59.7998 40.5
|
|
||||||
c-11.0996 7.5 -17.7998 20 -17.7998 33.5s6.59961 26 17.7998 33.5996l59.7998 40.5l-13.6992 71c-2.60059 13.2002 1.59961 26.7002 11.0996 36.3008c9.5 9.59961 23 13.6992 36.2998 11.1992l70.7998 -13.6992l40.4004 59.8994c15.0996 22.2998 51.9004 22.2998 67 0
|
|
||||||
l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9.5 -9.59961 13.7002 -23.2002 11.0996 -36.4004l-13.6992 -71zM381.3 140.5l76.7998 52.0996l-76.7998 52l17.6006 91.1006l-91 -17.6006l-51.9004 76.9004l-51.7998 -76.7998
|
|
||||||
l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136
|
|
||||||
c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" />
|
|
||||||
<glyph glyph-name="moon" unicode=""
|
|
||||||
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c13.0068 -0.00195312 33.9443 -1.91797 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
|
|
||||||
c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208
|
|
||||||
c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" />
|
|
||||||
<glyph glyph-name="caret-square-left" unicode="" horiz-adv-x="448"
|
|
||||||
d="M272 290.9v-197.801c0 -10.6992 -13 -16.0996 -20.5 -8.5l-98.2998 98.9004c-4.7002 4.7002 -4.7002 12.2002 0 16.9004l98.2998 98.8994c7.5 7.7002 20.5 2.2998 20.5 -8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
|
||||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="dot-circle" unicode=""
|
|
||||||
d="M256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200zM256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248z
|
|
||||||
M256 272c44.1826 0 80 -35.8174 80 -80s-35.8174 -80 -80 -80s-80 35.8174 -80 80s35.8174 80 80 80z" />
|
|
||||||
<glyph glyph-name="building" unicode="" horiz-adv-x="448"
|
|
||||||
d="M128 300v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12zM268 288c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40
|
|
||||||
c0 -6.59961 -5.40039 -12 -12 -12h-40zM140 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM268 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
|
||||||
c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM192 108c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM268 96c-6.59961 0 -12 5.40039 -12 12v40
|
|
||||||
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.59961 5.40039 12 12 12h19.5v440c0 13.2998 10.7002 24 24 24h337c13.2998 0 24 -10.7002 24 -24v-440h19.5
|
|
||||||
c6.59961 0 12 -5.40039 12 -12zM79.5 -15h112.5v67c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-67h112.5v414l-288.5 1z" />
|
|
||||||
<glyph glyph-name="file-pdf" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
|
||||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM298.2 127.7c10.5 -10.5 8 -38.7002 -17.5 -38.7002c-14.7998 0 -36.9004 6.7998 -55.7998 17c-21.6006 -3.59961 -46 -12.7002 -68.4004 -20.0996c-50.0996 -86.4004 -79.4004 -47 -76.0996 -31.2002
|
|
||||||
c4 20 31 35.8994 51 46.2002c10.5 18.3994 25.3994 50.5 35.3994 74.3994c-7.39941 28.6006 -11.3994 51 -7 67.1006c4.7998 17.6992 38.4004 20.2998 42.6006 -5.90039c4.69922 -15.4004 -1.5 -39.9004 -5.40039 -56c8.09961 -21.2998 19.5996 -35.7998 36.7998 -46.2998
|
|
||||||
c17.4004 2.2002 52.2002 5.5 64.4004 -6.5zM100.1 49.9004c0 -0.700195 11.4004 4.69922 30.4004 35c-5.90039 -5.5 -25.2998 -21.3008 -30.4004 -35zM181.7 240.5c-2.5 0 -2.60059 -26.9004 1.7998 -40.7998c4.90039 8.7002 5.59961 40.7998 -1.7998 40.7998zM157.3 103.9
|
|
||||||
c15.9004 6.09961 34 14.8994 54.7998 19.1992c-11.1992 8.30078 -21.7998 20.4004 -30.0996 35.5c-6.7002 -17.6992 -15 -37.7998 -24.7002 -54.6992zM288.9 108.9c3.59961 2.39941 -2.2002 10.3994 -37.3008 7.7998c32.3008 -13.7998 37.3008 -7.7998 37.3008 -7.7998z" />
|
|
||||||
<glyph glyph-name="file-word" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
|
||||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM268.1 192v0.200195h15.8008c7.7998 0 13.5 -7.2998 11.5996 -14.9004c-4.2998 -17 -13.7002 -54.0996 -34.5 -136c-1.2998 -5.39941 -6.09961 -9.09961 -11.5996 -9.09961h-24.7002
|
|
||||||
c-5.5 0 -10.2998 3.7998 -11.6006 9.09961c-5.2998 20.9004 -17.7998 71 -17.8994 71.4004l-2.90039 17.2998c-0.5 -5.2998 -1.5 -11.0996 -3 -17.2998l-17.8994 -71.4004c-1.30078 -5.39941 -6.10059 -9.09961 -11.6006 -9.09961h-25.2002
|
|
||||||
c-5.59961 0 -10.3994 3.7002 -11.6992 9.09961c-6.5 26.5 -25.2002 103.4 -33.2002 136c-1.7998 7.5 3.89941 14.7998 11.7002 14.7998h16.7998c5.7998 0 10.7002 -4.09961 11.7998 -9.69922c5 -25.7002 18.4004 -93.8008 19.0996 -99
|
|
||||||
c0.300781 -1.7002 0.400391 -3.10059 0.5 -4.2002c0.800781 7.5 0.400391 4.7002 24.8008 103.7c1.39941 5.2998 6.19922 9.09961 11.6992 9.09961h13.3008c5.59961 0 10.3994 -3.7998 11.6992 -9.2002c23.9004 -99.7002 22.8008 -94.3994 23.6006 -99.5
|
|
||||||
c0.299805 -1.7002 0.5 -3.09961 0.700195 -4.2998c0.599609 8.09961 0.399414 5.7998 21 103.5c1.09961 5.5 6 9.5 11.6992 9.5z" />
|
|
||||||
<glyph glyph-name="file-excel" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
|
||||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM260 224c9.2002 0 15 -10 10.2998 -18c-16 -27.5 -45.5996 -76.9004 -46.2998 -78l46.4004 -78c4.59961 -8 -1.10059 -18 -10.4004 -18h-28.7998c-4.40039 0 -8.5 2.40039 -10.6006 6.2998
|
|
||||||
c-22.6992 41.7998 -13.6992 27.5 -28.5996 57.7002c-5.59961 -12.7002 -6.90039 -17.7002 -28.5996 -57.7002c-2.10059 -3.89941 -6.10059 -6.2998 -10.5 -6.2998h-28.9004c-9.2998 0 -15.0996 10 -10.4004 18l46.3008 78l-46.3008 78c-4.59961 8 1.10059 18 10.4004 18
|
|
||||||
h28.9004c4.39941 0 8.5 -2.40039 10.5996 -6.2998c21.7002 -40.4004 14.7002 -28.6006 28.5996 -57.7002c6.40039 15.2998 10.6006 24.5996 28.6006 57.7002c2.09961 3.89941 6.09961 6.2998 10.5 6.2998h28.7998z" />
|
|
||||||
<glyph glyph-name="file-powerpoint" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
|
||||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM120 44v168c0 6.59961 5.40039 12 12 12h69.2002c36.7002 0 62.7998 -27 62.7998 -66.2998c0 -74.2998 -68.7002 -66.5 -95.5 -66.5v-47.2002c0 -6.59961 -5.40039 -12 -12 -12h-24.5c-6.59961 0 -12 5.40039 -12 12z
|
|
||||||
M168.5 131.4h23c7.90039 0 13.9004 2.39941 18.0996 7.19922c8.5 9.80078 8.40039 28.5 0.100586 37.8008c-4.10059 4.59961 -9.90039 7 -17.4004 7h-23.8994v-52h0.0996094z" />
|
|
||||||
<glyph glyph-name="file-image" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
|
||||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM80 32v64l39.5 39.5c4.7002 4.7002 12.2998 4.7002 17 0l39.5 -39.5l87.5 87.5c4.7002 4.7002 12.2998 4.7002 17 0l23.5 -23.5v-128h-224zM128 272c26.5 0 48 -21.5 48 -48s-21.5 -48 -48 -48s-48 21.5 -48 48
|
|
||||||
s21.5 48 48 48z" />
|
|
||||||
<glyph glyph-name="file-archive" unicode="" horiz-adv-x="384"
|
|
||||||
d="M128.3 288h32v-32h-32v32zM192.3 384v-32h-32v32h32zM128.3 352h32v-32h-32v32zM192.3 320v-32h-32v32h32zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1
|
|
||||||
c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-48.2998v-16h-32v16h-79.7002v-416h288zM194.2 182.3l17.2998 -87.7002c6.40039 -32.3994 -18.4004 -62.5996 -51.5 -62.5996
|
|
||||||
c-33.2002 0 -58 30.4004 -51.4004 62.9004l19.7002 97.0996v32h32v-32h22.1006c5.7998 0 10.6992 -4.09961 11.7998 -9.7002zM160.3 57.9004c17.9004 0 32.4004 12.0996 32.4004 27c0 14.8994 -14.5 27 -32.4004 27c-17.8994 0 -32.3994 -12.1006 -32.3994 -27
|
|
||||||
c0 -14.9004 14.5 -27 32.3994 -27zM192.3 256v-32h-32v32h32z" />
|
|
||||||
<glyph glyph-name="file-audio" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.941 350.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM332.118 320
|
|
||||||
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM192 60.0244c0 -10.6914 -12.9258 -16.0459 -20.4854 -8.48535l-35.5146 35.9746h-28c-6.62695 0 -12 5.37305 -12 12v56c0 6.62695 5.37305 12 12 12h28
|
|
||||||
l35.5146 36.9473c7.56055 7.56055 20.4854 2.20605 20.4854 -8.48535v-135.951zM233.201 107.154c9.05078 9.29688 9.05957 24.1328 0.000976562 33.4385c-22.1494 22.752 12.2344 56.2461 34.3945 33.4814c27.1982 -27.9404 27.2119 -72.4443 0.000976562 -100.401
|
|
||||||
c-21.793 -22.3857 -56.9463 10.3154 -34.3965 33.4814z" />
|
|
||||||
<glyph glyph-name="file-video" unicode="" horiz-adv-x="384"
|
|
||||||
d="M369.941 350.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM332.118 320
|
|
||||||
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM276.687 195.303c10.0049 10.0049 27.3135 2.99707 27.3135 -11.3135v-111.976c0 -14.2939 -17.2959 -21.332 -27.3135 -11.3135l-52.6865 52.6738v-37.374
|
|
||||||
c0 -11.0459 -8.9541 -20 -20 -20h-104c-11.0459 0 -20 8.9541 -20 20v104c0 11.0459 8.9541 20 20 20h104c11.0459 0 20 -8.9541 20 -20v-37.374z" />
|
|
||||||
<glyph glyph-name="file-code" unicode="" horiz-adv-x="384"
|
|
||||||
d="M149.9 98.9004c3.5 -3.30078 3.69922 -8.90039 0.399414 -12.4004l-17.3994 -18.5996c-1.60059 -1.80078 -4 -2.80078 -6.40039 -2.80078c-2.2002 0 -4.40039 0.900391 -6 2.40039l-57.7002 54.0996c-3.7002 3.40039 -3.7002 9.30078 0 12.8008l57.7002 54.0996
|
|
||||||
c3.40039 3.2998 9 3.2002 12.4004 -0.400391l17.3994 -18.5996l0.200195 -0.200195c3.2002 -3.59961 2.7998 -9.2002 -0.799805 -12.3994l-32.7998 -28.9004l32.7998 -28.9004zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288
|
|
||||||
c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288zM209.6 234l24.4004 -7
|
|
||||||
c4.7002 -1.2998 7.40039 -6.2002 6 -10.9004l-54.7002 -188.199c-1.2998 -4.60059 -6.2002 -7.40039 -10.8994 -6l-24.4004 7.09961c-4.7002 1.2998 -7.40039 6.2002 -6 10.9004l54.7002 188.1c1.39941 4.7002 6.2002 7.40039 10.8994 6zM234.1 157.1
|
|
||||||
c-3.5 3.30078 -3.69922 8.90039 -0.399414 12.4004l17.3994 18.5996c3.30078 3.60059 8.90039 3.7002 12.4004 0.400391l57.7002 -54.0996c3.7002 -3.40039 3.7002 -9.30078 0 -12.8008l-57.7002 -54.0996c-3.5 -3.2998 -9.09961 -3.09961 -12.4004 0.400391
|
|
||||||
l-17.3994 18.5996l-0.200195 0.200195c-3.2002 3.59961 -2.7998 9.2002 0.799805 12.3994l32.7998 28.9004l-32.7998 28.9004z" />
|
|
||||||
<glyph glyph-name="life-ring" unicode=""
|
|
||||||
d="M256 -56c-136.967 0 -248 111.033 -248 248s111.033 248 248 248s248 -111.033 248 -248s-111.033 -248 -248 -248zM152.602 20.7197c63.2178 -38.3184 143.579 -38.3184 206.797 0l-53.4111 53.4111c-31.8467 -13.5215 -68.168 -13.5059 -99.9746 0zM336 192
|
|
||||||
c0 44.1123 -35.8877 80 -80 80s-80 -35.8877 -80 -80s35.8877 -80 80 -80s80 35.8877 80 80zM427.28 88.6016c38.3184 63.2178 38.3184 143.579 0 206.797l-53.4111 -53.4111c13.5215 -31.8467 13.5049 -68.168 0 -99.9746zM359.397 363.28
|
|
||||||
c-63.2168 38.3184 -143.578 38.3184 -206.796 0l53.4111 -53.4111c31.8457 13.5215 68.167 13.5049 99.9736 0zM84.7197 295.398c-38.3184 -63.2178 -38.3184 -143.579 0 -206.797l53.4111 53.4111c-13.5215 31.8467 -13.5059 68.168 0 99.9746z" />
|
|
||||||
<glyph glyph-name="paper-plane" unicode=""
|
|
||||||
d="M440 441.5c34.5996 19.9004 77.5996 -8.7998 71.5 -48.9004l-59.4004 -387.199c-2.2998 -14.5 -11.0996 -27.3008 -23.8994 -34.5c-7.2998 -4.10059 -15.4004 -6.2002 -23.6006 -6.2002c-6.19922 0 -12.3994 1.2002 -18.2998 3.59961l-111.899 46.2002l-43.8008 -59.0996
|
|
||||||
c-27.3994 -36.9004 -86.5996 -17.8008 -86.5996 28.5996v84.4004l-114.3 47.2998c-36.7998 15.0996 -40.1006 66 -5.7002 85.8994zM192 -16l36.5996 49.5l-36.5996 15.0996v-64.5996zM404.6 12.7002l59.4004 387.3l-416 -240l107.8 -44.5996l211.5 184.3
|
|
||||||
c14.2002 12.2998 34.4004 -5.7002 23.7002 -21.2002l-140.2 -202.3z" />
|
|
||||||
<glyph glyph-name="futbol" unicode="" horiz-adv-x="496"
|
|
||||||
d="M483.8 268.6c42.2998 -130.199 -29 -270.1 -159.2 -312.399c-25.5 -8.2998 -51.2998 -12.2002 -76.6992 -12.2002c-104.5 0 -201.7 66.5996 -235.7 171.4c-42.2998 130.199 29 270.1 159.2 312.399c25.5 8.2998 51.2998 12.2002 76.6992 12.2002
|
|
||||||
c104.5 0 201.7 -66.5996 235.7 -171.4zM409.3 74.9004c6.10059 8.39941 12.1006 16.8994 16.7998 26.1992c14.3008 28.1006 21.5 58.5 21.7002 89.2002l-38.8994 36.4004l-71.1006 -22.1006l-24.3994 -75.1992l43.6992 -60.9004zM409.3 310.3
|
|
||||||
c-24.5 33.4004 -58.7002 58.4004 -97.8994 71.4004l-47.4004 -26.2002v-73.7998l64.2002 -46.5l70.7002 22zM184.9 381.6c-39.9004 -13.2998 -73.5 -38.5 -97.8008 -71.8994l10.1006 -52.5l70.5996 -22l64.2002 46.5v73.7998zM139 68.5l43.5 61.7002l-24.2998 74.2998
|
|
||||||
l-71.1006 22.2002l-39 -36.4004c0.5 -55.7002 23.4004 -95.2002 37.8008 -115.3zM187.2 1.5c64.0996 -20.4004 115.5 -1.7998 121.7 0l22.3994 48.0996l-44.2998 61.7002h-78.5996l-43.6006 -61.7002z" />
|
|
||||||
<glyph glyph-name="newspaper" unicode="" horiz-adv-x="576"
|
|
||||||
d="M552 384c13.2549 0 24 -10.7451 24 -24v-336c0 -13.2549 -10.7451 -24 -24 -24h-496c-30.9277 0 -56 25.0723 -56 56v272c0 13.2549 10.7451 24 24 24h42.752c6.60547 18.623 24.3896 32 45.248 32h440zM48 56c0 -4.41113 3.58887 -8 8 -8s8 3.58887 8 8v248h-16v-248z
|
|
||||||
M528 48v288h-416v-280c0 -2.7168 -0.204102 -5.38574 -0.578125 -8h416.578zM172 168c-6.62695 0 -12 5.37305 -12 12v96c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-96c0 -6.62695 -5.37305 -12 -12 -12h-136zM200 248v-40h80v40h-80zM160 108v24
|
|
||||||
c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-136c-6.62695 0 -12 5.37305 -12 12zM352 108v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104
|
|
||||||
c-6.62695 0 -12 5.37305 -12 12zM352 252v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12zM352 180v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24
|
|
||||||
c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12z" />
|
|
||||||
<glyph glyph-name="bell-slash" unicode="" horiz-adv-x="640"
|
|
||||||
d="M633.99 -23.0195c6.91016 -5.52051 8.01953 -15.5908 2.5 -22.4902l-10 -12.4902c-5.53027 -6.88965 -15.5898 -8.00977 -22.4902 -2.49023l-598 467.51c-6.90039 5.52051 -8.01953 15.5908 -2.49023 22.4902l10 12.4902
|
|
||||||
c5.52051 6.90039 15.5898 8.00977 22.4902 2.49023zM163.53 80h182.84l61.3994 -48h-279.659c-19.1201 0 -31.9902 15.5996 -32.1006 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c18.3701 19.7402 51.5703 49.6904 54.8398 140.42l45.4697 -35.5498
|
|
||||||
c-6.91992 -54.7803 -24.6895 -88.5498 -41.3994 -110.58zM320 352c-23.3496 0 -45 -7.17969 -62.9404 -19.4004l-38.1699 29.8408c19.6807 15.7793 43.1104 27.3096 69.1299 32.7197v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398
|
|
||||||
c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -41.3604 6.03027 -70.7197 14.3398 -92.8496l-59.5293 46.54c-1.63086 13.96 -2.77051 28.8896 -2.79004 45.7295c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112zM320 -64
|
|
||||||
c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
|
||||||
<glyph glyph-name="copyright" unicode=""
|
|
||||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
|
||||||
M363.351 93.0645c-9.61328 -9.71289 -45.5293 -41.3965 -104.064 -41.3965c-82.4297 0 -140.484 61.4248 -140.484 141.567c0 79.1514 60.2754 139.4 139.763 139.4c55.5303 0 88.7373 -26.6201 97.5928 -34.7783c2.13379 -1.96289 3.86523 -5.9082 3.86523 -8.80762
|
|
||||||
c0 -1.95508 -0.864258 -4.87402 -1.92969 -6.51465l-18.1543 -28.1133c-3.8418 -5.9502 -11.9668 -7.28223 -17.499 -2.9209c-8.5957 6.77637 -31.8145 22.5381 -61.708 22.5381c-48.3037 0 -77.916 -35.3301 -77.916 -80.082c0 -41.5889 26.8877 -83.6924 78.2764 -83.6924
|
|
||||||
c32.6572 0 56.8428 19.0391 65.7266 27.2256c5.26953 4.85645 13.5957 4.03906 17.8193 -1.73828l19.8652 -27.1699c1.28613 -1.74512 2.33008 -4.91992 2.33008 -7.08789c0 -2.72363 -1.56055 -6.5 -3.48242 -8.42969z" />
|
|
||||||
<glyph glyph-name="closed-captioning" unicode=""
|
|
||||||
d="M464 384c26.5 0 48 -21.5 48 -48v-288c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h416zM458 48c3.2998 0 6 2.7002 6 6v276c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-276c0 -3.2998 2.7002 -6 6 -6h404z
|
|
||||||
M246.9 133.7c1.69922 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.6006 -56.7998 -172.801 -32.0996 -172.801 67.9004c0 97.2998 121.7 119.5 172.5 70.0996c2.10059 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.89941 -3.09961 -6.19922 -4 -9.09961 -1.7002
|
|
||||||
c-40.7998 32 -94.5996 14.9004 -94.5996 -31.1992c0 -48 51 -70.5 92.1992 -32.6006c2.80078 2.5 7.10059 2.10059 9.2002 -0.899414zM437.3 133.7c1.7002 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.5996 -56.9004 -172.8 -32.0996 -172.8 67.9004
|
|
||||||
c0 97.2998 121.7 119.5 172.5 70.0996c2.09961 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.90039 -3.09961 -6.2002 -4 -9.09961 -1.7002c-40.8008 32 -94.6006 14.9004 -94.6006 -31.1992c0 -48 51 -70.5 92.2002 -32.6006c2.7998 2.5 7.09961 2.10059 9.2002 -0.899414z
|
|
||||||
" />
|
|
||||||
<glyph glyph-name="object-group" unicode=""
|
|
||||||
d="M500 320h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v256h-12
|
|
||||||
c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM448 384v-32h32v32h-32zM32 384v-32h32v32h-32zM64 0v32
|
|
||||||
h-32v-32h32zM480 0v32h-32v-32h32zM440 64v256h-12c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h12zM404 256c6.62695 0 12 -5.37207 12 -12v-168
|
|
||||||
c0 -6.62793 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37207 -12 12v52h-84c-6.62695 0 -12 5.37207 -12 12v168c0 6.62793 5.37305 12 12 12h200c6.62695 0 12 -5.37207 12 -12v-52h84zM136 280v-112h144v112h-144zM376 104v112h-56v-76
|
|
||||||
c0 -6.62793 -5.37305 -12 -12 -12h-76v-24h144z" />
|
|
||||||
<glyph glyph-name="object-ungroup" unicode="" horiz-adv-x="576"
|
|
||||||
d="M564 224h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v24h-88v-12
|
|
||||||
c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h72
|
|
||||||
c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-12v-24h88v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM352 384v-32h32v32h-32zM352 128v-32h32v32h-32zM64 96v32h-32v-32h32zM64 352v32
|
|
||||||
h-32v-32h32zM96 136h224v12c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-12zM224 0v32h-32v-32h32zM504 64v160h-12c-6.62695 0 -12 5.37305 -12 12v12
|
|
||||||
h-88v-88h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-88v-24h12c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h12zM544 0v32h-32v-32h32zM544 256v32h-32v-32h32z" />
|
|
||||||
<glyph glyph-name="sticky-note" unicode="" horiz-adv-x="448"
|
|
||||||
d="M448 99.8936c0 -10.9746 -6.29883 -26.1797 -14.0586 -33.9404l-83.8828 -83.8818c-7.75977 -7.76074 -22.9658 -14.0596 -33.9404 -14.0596h-268.118c-26.5098 0 -48 21.4902 -48 48v351.988c0 26.5098 21.4902 48 48 48h352c26.5098 0 48 -21.4902 48 -48v-268.106z
|
|
||||||
M320 19.8936l76.1182 76.1182h-76.1182v-76.1182zM400 368h-352v-351.988h224v104c0 13.2549 10.7451 24 24 24h104v223.988z" />
|
|
||||||
<glyph glyph-name="clone" unicode=""
|
|
||||||
d="M464 448c26.5098 0 48 -21.4902 48 -48v-320c0 -26.5098 -21.4902 -48 -48 -48h-48v-48c0 -26.5098 -21.4902 -48 -48 -48h-320c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h48v48c0 26.5098 21.4902 48 48 48h320zM362 -16c3.31152 0 6 2.68848 6 6
|
|
||||||
v42h-224c-26.5098 0 -48 21.4902 -48 48v224h-42c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308zM458 80c3.31152 0 6 2.68848 6 6v308c0 3.31152 -2.68848 6 -6 6h-308c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308z" />
|
|
||||||
<glyph glyph-name="hourglass" unicode="" horiz-adv-x="384"
|
|
||||||
d="M368 400c0 -80.0996 -31.8984 -165.619 -97.1797 -208c64.9912 -42.1934 97.1797 -127.436 97.1797 -208h4c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-360c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h4
|
|
||||||
c0 80.0996 31.8994 165.619 97.1797 208c-64.9912 42.1934 -97.1797 127.436 -97.1797 208h-4c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h360c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-4zM64 400
|
|
||||||
c0 -101.621 57.3066 -184 128 -184s128 82.3799 128 184h-256zM320 -16c0 101.62 -57.3076 184 -128 184s-128 -82.3799 -128 -184h256z" />
|
|
||||||
<glyph glyph-name="hand-rock" unicode=""
|
|
||||||
d="M408.864 368.948c48.8213 20.751 103.136 -15.0723 103.136 -67.9111v-114.443c0 -15.3955 -3.08887 -30.3906 -9.18262 -44.5674l-42.835 -99.6562c-4.99707 -11.625 -3.98242 -18.8574 -3.98242 -42.3701c0 -17.6729 -14.3271 -32 -32 -32h-252
|
|
||||||
c-17.6729 0 -32 14.3271 -32 32c0 27.3301 1.1416 29.2012 -3.11035 32.9033l-97.71 85.0811c-24.8994 21.6797 -39.1797 52.8926 -39.1797 85.6338v56.9531c0 47.4277 44.8457 82.0215 91.0459 71.1807c1.96094 55.751 63.5107 87.8262 110.671 60.8057
|
|
||||||
c29.1895 31.0713 78.8604 31.4473 108.334 -0.0214844c32.7051 18.6846 76.4121 10.3096 98.8135 -23.5879zM464 186.594v114.445c0 34.29 -52 33.8232 -52 0.676758c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v26.751
|
|
||||||
c0 34.457 -52 33.707 -52 0.676758v-27.4287c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v40.4658c0 34.3525 -52 33.8115 -52 0.677734v-41.1436c0 -8.83594 -7.16406 -16 -16 -16h-7c-8.83594 0 -16 7.16406 -16 16v26.751
|
|
||||||
c0 34.4023 -52 33.7744 -52 0.676758v-116.571c0 -8.83203 -7.16797 -16 -16 -16c-3.30664 0 -8.01367 1.7627 -10.5068 3.93359l-7 6.09473c-3.03223 2.64062 -5.49316 8.04688 -5.49316 12.0674v0v41.2275c0 34.2148 -52 33.8857 -52 0.677734v-56.9531
|
|
||||||
c0 -18.8555 8.27441 -36.874 22.7002 -49.4365l97.71 -85.0801c12.4502 -10.8398 19.5898 -26.4463 19.5898 -42.8164v-10.2861h220v7.07617c0 13.21 2.65332 26.0791 7.88281 38.25l42.835 99.6553c2.91602 6.75391 5.28223 18.207 5.28223 25.5635v0.0488281z" />
|
|
||||||
<glyph glyph-name="hand-paper" unicode="" horiz-adv-x="448"
|
|
||||||
d="M372.57 335.359c39.9062 5.63281 75.4297 -25.7393 75.4297 -66.3594v-131.564c-0.00195312 -12.7666 -2.33008 -33.2246 -5.19531 -45.666l-30.1836 -130.958c-3.34668 -14.5234 -16.2783 -24.8125 -31.1816 -24.8125h-222.897
|
|
||||||
c-9.10352 0 -20.7793 6.01758 -26.0615 13.4316l-119.97 168.415c-21.2441 29.8203 -14.8047 71.3574 14.5498 93.1533c18.7754 13.9395 42.1309 16.2979 62.083 8.87109v126.13c0 44.0547 41.125 75.5439 82.4053 64.9834c23.8926 48.1963 92.3535 50.2471 117.982 0.74707
|
|
||||||
c42.5186 11.1445 83.0391 -21.9346 83.0391 -65.5469v-10.8242zM399.997 137.437l-0.00195312 131.563c0 24.9492 -36.5703 25.5508 -36.5703 -0.691406v-76.3086c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v154.184
|
|
||||||
c0 25.501 -36.5703 26.3633 -36.5703 0.691406v-154.875c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v188.309c0 25.501 -36.5703 26.3545 -36.5703 0.691406v-189c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16
|
|
||||||
v153.309c0 25.501 -36.5713 26.3359 -36.5713 0.691406v-206.494c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832l-27.1279 38.0791c-14.3711 20.1709 -43.833 -2.33496 -29.3945 -22.6045l115.196 -161.697h201.92l27.3252 118.551
|
|
||||||
c2.63086 11.417 3.96484 23.1553 3.96484 34.8857z" />
|
|
||||||
<glyph glyph-name="hand-scissors" unicode=""
|
|
||||||
d="M256 -32c-44.9561 0 -77.3428 43.2627 -64.0244 85.8535c-21.6484 13.71 -34.0156 38.7617 -30.3408 65.0068h-87.6348c-40.8037 0 -74 32.8105 -74 73.1406c0 40.3291 33.1963 73.1396 74 73.1396l94 -9.14062l-78.8496 18.6787
|
|
||||||
c-38.3076 14.7422 -57.04 57.4707 -41.9424 95.1123c15.0303 37.4736 57.7549 55.7803 95.6416 41.2012l144.929 -55.7568c24.9551 30.5566 57.8086 43.9932 92.2178 24.7324l97.999 -54.8525c20.9746 -11.7393 34.0049 -33.8457 34.0049 -57.6904v-205.702
|
|
||||||
c0 -30.7422 -21.4404 -57.5576 -51.7979 -64.5537l-118.999 -27.4268c-4.97168 -1.14648 -10.0889 -1.72949 -15.2031 -1.72949zM256 16.0127l70 -0.000976562c1.23633 0 3.21777 0.225586 4.42285 0.501953l119.001 27.4277
|
|
||||||
c8.58203 1.97754 14.5762 9.29102 14.5762 17.7812v205.701c0 6.4873 -3.62109 12.542 -9.44922 15.8047l-98 54.8545c-8.13965 4.55566 -18.668 2.61914 -24.4873 -4.50781l-21.7646 -26.6475c-2.65039 -3.24512 -8.20215 -5.87891 -12.3926 -5.87891
|
|
||||||
c-1.64062 0 -4.21484 0.477539 -5.74609 1.06738l-166.549 64.0908c-32.6543 12.5664 -50.7744 -34.5771 -19.2227 -46.7168l155.357 -59.7852c5.66016 -2.17773 10.2539 -8.86816 10.2539 -14.9326v0v-11.6328c0 -8.83691 -7.16309 -16 -16 -16h-182
|
|
||||||
c-34.375 0 -34.4297 -50.2803 0 -50.2803h182c8.83691 0 16 -7.16309 16 -16v-6.85645c0 -8.83691 -7.16309 -16 -16 -16h-28c-25.1221 0 -25.1592 -36.5674 0 -36.5674h28c8.83691 0 16 -7.16211 16 -16v-6.85547c0 -8.83691 -7.16309 -16 -16 -16
|
|
||||||
c-25.1201 0 -25.1602 -36.5674 0 -36.5674z" />
|
|
||||||
<glyph glyph-name="hand-lizard" unicode="" horiz-adv-x="576"
|
|
||||||
d="M556.686 157.458c12.6357 -19.4863 19.3145 -42.0615 19.3145 -65.2871v-124.171h-224v71.582l-99.751 38.7871c-2.7832 1.08203 -5.70996 1.63086 -8.69727 1.63086h-131.552c-30.8789 0 -56 25.1211 -56 56c0 48.5234 39.4766 88 88 88h113.709l18.333 48h-196.042
|
|
||||||
c-44.1123 0 -80 35.8877 -80 80v8c0 30.8779 25.1211 56 56 56h293.917c24.5 0 47.084 -12.2725 60.4111 -32.8291zM528 16v76.1709v0.0478516c0 11.7461 -5.19141 29.2734 -11.5879 39.124l-146.358 225.715c-4.44336 6.85254 -11.9707 10.9424 -20.1367 10.9424h-293.917
|
|
||||||
c-4.41113 0 -8 -3.58887 -8 -8v-8c0 -17.6445 14.3555 -32 32 -32h213.471c25.2021 0 42.626 -25.293 33.6299 -48.8457l-24.5518 -64.2812c-7.05371 -18.4658 -25.0732 -30.873 -44.8398 -30.873h-113.709c-22.0557 0 -40 -17.9443 -40 -40c0 -4.41113 3.58887 -8 8 -8
|
|
||||||
h131.552h0.0517578c7.44141 0 19.1074 -2.19238 26.041 -4.89355l99.752 -38.7881c18.5898 -7.22852 30.6035 -24.7881 30.6035 -44.7363v-23.582h128z" />
|
|
||||||
<glyph glyph-name="hand-spock" unicode=""
|
|
||||||
d="M501.03 331.824c6.05762 -9.77832 10.9746 -27.0498 10.9746 -38.5518c0 -4.80664 -0.915039 -12.499 -2.04297 -17.1709l-57.623 -241.963c-12.748 -54.1729 -68.2627 -98.1387 -123.915 -98.1387h-0.345703h-107.455h-0.224609
|
|
||||||
c-33.8135 0 -81.2148 18.834 -105.807 42.041l-91.3652 85.9766c-12.8213 12.0469 -23.2266 36.1016 -23.2266 53.6943c0 16.1299 8.97266 38.7529 20.0273 50.499c5.31836 5.66406 29.875 29.3926 68.1152 21.8477l-24.3594 82.1973
|
|
||||||
c-1.68164 5.66406 -3.0459 15.0576 -3.0459 20.9668c0 37.5938 30.417 70.502 67.8955 73.4551c-0.204102 2.03125 -0.369141 5.33691 -0.369141 7.37891c0 31.627 24.8594 63.6895 55.4902 71.5684c43.248 10.9785 80.5645 -17.7012 89.6602 -53.0723l13.6836 -53.207
|
|
||||||
l4.64648 22.6602c6.76074 32.417 39.123 58.8115 72.2373 58.916c8.73438 0 56.625 -3.26953 70.7383 -54.0801c15.0664 0.710938 46.9199 -3.50977 66.3105 -35.0176zM463.271 287.219c7.86914 32.9844 -42.1211 45.2695 -50.0859 11.9219l-24.8008 -104.146
|
|
||||||
c-4.38867 -18.4141 -31.7783 -11.8926 -28.0557 6.2168l28.5479 139.166c7.39844 36.0703 -43.3076 45.0703 -50.1182 11.9629l-31.791 -154.971c-3.54883 -17.3086 -28.2832 -18.0469 -32.7109 -0.804688l-47.3262 184.035
|
|
||||||
c-8.43359 32.8105 -58.3691 20.2676 -49.8652 -12.8359l42.4414 -165.039c4.81641 -18.7207 -23.3711 -26.9121 -28.9648 -8.00781l-31.3438 105.779c-9.6875 32.6465 -59.1191 18.2578 -49.3867 -14.625l36.0137 -121.539
|
|
||||||
c5.61816 -18.9521 10.1777 -50.377 10.1777 -70.1436v-0.00878906c0 -6.54297 -8.05664 -10.9355 -13.4824 -5.82617l-51.123 48.1074c-24.7852 23.4082 -60.0527 -14.1875 -35.2793 -37.4902l91.3691 -85.9805c16.9629 -16.0068 49.6592 -28.998 72.9824 -28.998h0.154297
|
|
||||||
h107.455h0.216797c34.7402 0 69.3936 27.4443 77.3525 61.2598z" />
|
|
||||||
<glyph glyph-name="hand-pointer" unicode="" horiz-adv-x="448"
|
|
||||||
d="M358.182 268.639c43.1934 16.6348 89.8184 -15.7949 89.8184 -62.6387v-84c-0.000976562 -4.25 -0.775391 -11.0615 -1.72754 -15.2041l-27.4297 -118.999c-6.98242 -30.2969 -33.7549 -51.7969 -64.5566 -51.7969h-178.286c-21.2588 0 -41.3682 10.4102 -53.791 27.8457
|
|
||||||
l-109.699 154.001c-21.2432 29.8193 -14.8047 71.3574 14.5498 93.1523c18.8115 13.9658 42.1748 16.2822 62.083 8.87207v161.129c0 36.9443 29.7363 67 66.2861 67s66.2861 -30.0557 66.2861 -67v-73.6338c20.4131 2.85742 41.4678 -3.94238 56.5947 -19.6289
|
|
||||||
c27.1934 12.8467 60.3799 5.66992 79.8721 -19.0986zM80.9854 168.303c-14.4004 20.2119 -43.8008 -2.38281 -29.3945 -22.6055l109.712 -154c3.43457 -4.81934 8.92871 -7.69727 14.6973 -7.69727h178.285c8.49219 0 15.8037 5.99414 17.7822 14.5762l27.4297 119.001
|
|
||||||
c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285v84c0 25.1602 -36.5713 25.1211 -36.5713 0c0 -8.83594 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16406 -16 16v21c0 25.1602 -36.5713 25.1201 -36.5713 0v-21c0 -8.83594 -7.16309 -16 -16 -16h-6.85938
|
|
||||||
c-8.83691 0 -16 7.16406 -16 16v35c0 25.1602 -36.5703 25.1201 -36.5703 0v-35c0 -8.83594 -7.16309 -16 -16 -16h-6.85742c-8.83691 0 -16 7.16406 -16 16v175c0 25.1602 -36.5713 25.1201 -36.5713 0v-241.493c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832z
|
|
||||||
M176.143 48v96c0 8.83691 6.26855 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM251.571 48v96c0 8.83691 6.26758 16 14 16h6c7.73145 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26855 -16 -14 -16h-6
|
|
||||||
c-7.73242 0 -14 7.16309 -14 16zM327 48v96c0 8.83691 6.26758 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16z" />
|
|
||||||
<glyph glyph-name="hand-peace" unicode="" horiz-adv-x="448"
|
|
||||||
d="M362.146 256.024c42.5908 13.3184 85.8535 -19.0684 85.8535 -64.0244l-0.0117188 -70.001c-0.000976562 -4.25 -0.775391 -11.0615 -1.72949 -15.2031l-27.4268 -118.999c-6.99707 -30.3564 -33.8105 -51.7969 -64.5547 -51.7969h-205.702
|
|
||||||
c-23.8447 0 -45.9502 13.0303 -57.6904 34.0059l-54.8525 97.999c-19.2607 34.4092 -5.82422 67.2617 24.7324 92.2178l-55.7568 144.928c-14.5791 37.8867 3.72754 80.6113 41.2012 95.6416c37.6406 15.0977 80.3691 -3.63477 95.1123 -41.9424l18.6787 -78.8496
|
|
||||||
l-9.14062 94c0 40.8037 32.8096 74 73.1396 74s73.1406 -33.1963 73.1406 -74v-87.6348c26.2451 3.6748 51.2959 -8.69238 65.0068 -30.3408zM399.987 122l-0.000976562 70c0 25.1602 -36.5674 25.1201 -36.5674 0c0 -8.83691 -7.16309 -16 -16 -16h-6.85547
|
|
||||||
c-8.83789 0 -16 7.16309 -16 16v28c0 25.1592 -36.5674 25.1221 -36.5674 0v-28c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v182c0 34.4297 -50.2803 34.375 -50.2803 0v-182c0 -8.83691 -7.16309 -16 -16 -16h-11.6328v0
|
|
||||||
c-6.06445 0 -12.7549 4.59375 -14.9326 10.2539l-59.7842 155.357c-12.1396 31.5518 -59.2842 13.4326 -46.7168 -19.2227l64.0898 -166.549c0.589844 -1.53125 1.06738 -4.10547 1.06738 -5.74609c0 -4.19043 -2.63379 -9.74219 -5.87891 -12.3926l-26.6475 -21.7646
|
|
||||||
c-7.12695 -5.81934 -9.06445 -16.3467 -4.50781 -24.4873l54.8535 -98c3.26367 -5.82812 9.31934 -9.44922 15.8057 -9.44922h205.701c8.49121 0 15.8037 5.99414 17.7812 14.5762l27.4277 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285z" />
|
|
||||||
<glyph glyph-name="registered" unicode=""
|
|
||||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
|
||||||
M366.442 73.791c4.40332 -7.99219 -1.37012 -17.791 -10.5107 -17.791h-42.8096h-0.0126953c-3.97559 0 -8.71582 2.84961 -10.5801 6.36035l-47.5156 89.3027h-31.958v-83.6631c0 -6.61719 -5.38281 -12 -12 -12h-38.5674c-6.61719 0 -12 5.38281 -12 12v248.304
|
|
||||||
c0 6.61719 5.38281 12 12 12h78.667c71.251 0 101.498 -32.749 101.498 -85.252c0 -31.6123 -15.2148 -59.2969 -39.4824 -73.1758c3.02148 -4.61719 0.225586 0.199219 53.2715 -96.085zM256.933 208.094c20.9131 0 32.4307 11.5186 32.4316 32.4316
|
|
||||||
c0 19.5752 -6.5127 31.709 -38.9297 31.709h-27.377v-64.1406h33.875z" />
|
|
||||||
<glyph glyph-name="calendar-plus" unicode="" horiz-adv-x="448"
|
|
||||||
d="M336 156v-24c0 -6.59961 -5.40039 -12 -12 -12h-76v-76c0 -6.59961 -5.40039 -12 -12 -12h-24c-6.59961 0 -12 5.40039 -12 12v76h-76c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h76v76c0 6.59961 5.40039 12 12 12h24c6.59961 0 12 -5.40039 12 -12
|
|
||||||
v-76h76c6.59961 0 12 -5.40039 12 -12zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40
|
|
||||||
c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="calendar-minus" unicode="" horiz-adv-x="448"
|
|
||||||
d="M124 120c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h200c6.59961 0 12 -5.40039 12 -12v-24c0 -6.59961 -5.40039 -12 -12 -12h-200zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52
|
|
||||||
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="calendar-times" unicode="" horiz-adv-x="448"
|
|
||||||
d="M311.7 73.2998l-17 -17c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-53.7002 53.7998l-53.7002 -53.6992c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-17 17c-4.7002 4.69922 -4.7002 12.2998 0 17l53.7002 53.6992l-53.7002 53.7002c-4.7002 4.7002 -4.7002 12.2998 0 17
|
|
||||||
l17 17c4.7002 4.7002 12.2998 4.7002 17 0l53.7002 -53.7002l53.7002 53.7002c4.7002 4.7002 12.2998 4.7002 17 0l17 -17c4.7002 -4.7002 4.7002 -12.2998 0 -17l-53.7998 -53.7998l53.6992 -53.7002c4.80078 -4.7002 4.80078 -12.2998 0.100586 -17zM448 336v-352
|
|
||||||
c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10
|
|
||||||
v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="calendar-check" unicode="" horiz-adv-x="448"
|
|
||||||
d="M400 384c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h48v52c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-52h128v52c0 6.62695 5.37305 12 12 12h40
|
|
||||||
c6.62695 0 12 -5.37305 12 -12v-52h48zM394 -16c3.31152 0 6 2.68848 6 6v298h-352v-298c0 -3.31152 2.68848 -6 6 -6h340zM341.151 184.65l-142.31 -141.169c-4.70508 -4.66699 -12.3027 -4.6377 -16.9707 0.0673828l-75.0908 75.6992
|
|
||||||
c-4.66699 4.70508 -4.6377 12.3027 0.0673828 16.9707l22.7197 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l44.1035 -44.4609l111.072 110.182c4.70508 4.66699 12.3027 4.63672 16.9707 -0.0683594l22.5361 -22.7178
|
|
||||||
c4.66699 -4.70508 4.63672 -12.3027 -0.0683594 -16.9697z" />
|
|
||||||
<glyph glyph-name="map" unicode="" horiz-adv-x="576"
|
|
||||||
d="M560.02 416c8.4502 0 15.9805 -6.83008 15.9805 -16.0195v-346.32c0 -11.9609 -9.01367 -25.2705 -20.1201 -29.71l-151.83 -52.8105c-5.32617 -1.7334 -14.1953 -3.13965 -19.7969 -3.13965c-5.7373 0 -14.8105 1.47363 -20.2529 3.29004l-172 60.71l-170.05 -62.8398
|
|
||||||
c-1.99023 -0.790039 -4 -1.16016 -5.95996 -1.16016c-8.45996 0 -15.9902 6.83008 -15.9902 16.0195v346.32c0.00292969 11.959 9.0166 25.2686 20.1201 29.71l151.83 52.8105c6.43945 2.08984 13.1201 3.13965 19.8096 3.13965
|
|
||||||
c5.73242 -0.00195312 14.8008 -1.47168 20.2402 -3.28027l172 -60.7197h0.00976562l170.05 62.8398c1.98047 0.790039 4 1.16016 5.95996 1.16016zM224 357.58v-285.97l128 -45.1904v285.97zM48 29.9502l127.36 47.0801l0.639648 0.229492v286.2l-128 -44.5303v-288.979z
|
|
||||||
M528 65.0801v288.97l-127.36 -47.0693l-0.639648 -0.240234v-286.19z" />
|
|
||||||
<glyph glyph-name="comment-alt" unicode=""
|
|
||||||
d="M448 448c35.2998 0 64 -28.7002 64 -64v-288c0 -35.2998 -28.7002 -64 -64 -64h-144l-124.9 -93.5996c-2.19922 -1.7002 -4.69922 -2.40039 -7.09961 -2.40039c-6.2002 0 -12 4.90039 -12 12v84h-96c-35.2998 0 -64 28.7002 -64 64v288c0 35.2998 28.7002 64 64 64h384z
|
|
||||||
M464 96v288c0 8.7998 -7.2002 16 -16 16h-384c-8.7998 0 -16 -7.2002 -16 -16v-288c0 -8.7998 7.2002 -16 16 -16h144v-60l67.2002 50.4004l12.7998 9.59961h160c8.7998 0 16 7.2002 16 16z" />
|
|
||||||
<glyph glyph-name="pause-circle" unicode=""
|
|
||||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48
|
|
||||||
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16zM240 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16z" />
|
|
||||||
<glyph glyph-name="stop-circle" unicode=""
|
|
||||||
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-160
|
|
||||||
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h160c8.7998 0 16 -7.2002 16 -16z" />
|
|
||||||
<glyph glyph-name="handshake" unicode="" horiz-adv-x="640"
|
|
||||||
d="M519.2 320.1h120.8v-255.699h-64c-17.5 0 -31.7998 14.1992 -31.9004 31.6992h-57.8994c-1.7998 -8.19922 -5.2998 -16.0996 -10.9004 -23l-26.2002 -32.2998c-15.7998 -19.3994 -41.8994 -25.5 -64 -16.7998c-13.5 -16.5996 -30.5996 -24 -48.7998 -24
|
|
||||||
c-15.0996 0 -28.5996 5.09961 -41.0996 15.9004c-31.7998 -21.9004 -74.7002 -21.3008 -105.601 3.7998l-84.5996 76.3994h-9.09961c-0.100586 -17.5 -14.3008 -31.6992 -31.9004 -31.6992h-64v255.699h118l47.5996 47.6006c10.5 10.3994 24.8008 16.2998 39.6006 16.2998
|
|
||||||
h226.8v0c12.7812 0 30.5225 -7.30273 39.5996 -16.2998zM48 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16zM438 103.3c2.7002 3.40039 2.2002 8.5 -1.2002 11.2998l-108.2 87.8008l-8.19922 -7.5
|
|
||||||
c-40.3008 -36.8008 -86.7002 -11.8008 -101.5 4.39941c-26.7002 29 -25 74.4004 4.39941 101.3l38.7002 35.5h-56.7002c-2 -0.799805 -3.7002 -1.5 -5.7002 -2.2998l-61.6992 -61.5996h-41.9004v-128.101h27.7002l97.2998 -88
|
|
||||||
c16.0996 -13.0996 41.4004 -10.5 55.2998 6.60059l15.6006 19.2002l36.7998 -31.5c3 -2.40039 12 -4.90039 18 2.39941l30 36.5l23.8994 -19.3994c3.5 -2.80078 8.5 -2.2002 11.3008 1.19922zM544 144.1v128h-44.7002l-61.7002 61.6006
|
|
||||||
c-1.39941 1.5 -3.39941 2.2998 -5.5 2.2998l-83.6992 -0.200195c-10 0 -19.6006 -3.7002 -27 -10.5l-65.6006 -60.0996c-9.7002 -8.7998 -10.5 -24 -1.2002 -33.9004c8.90039 -9.39941 25.1006 -8.7002 34.6006 0l55.2002 50.6006c6.5 5.89941 16.5996 5.5 22.5996 -1
|
|
||||||
l10.9004 -11.7002c6 -6.5 5.5 -16.6006 -1 -22.6006l-12.5 -11.3994l102.699 -83.4004c2.80078 -2.2998 5.40039 -4.89941 7.7002 -7.7002h69.2002zM592 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16z
|
|
||||||
" />
|
|
||||||
<glyph glyph-name="envelope-open" unicode=""
|
|
||||||
d="M494.586 283.484c9.6123 -7.94824 17.4141 -24.5205 17.4141 -36.9932v-262.491c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v262.515c0 12.5166 7.84668 29.1279 17.5146 37.0771c4.08008 3.35449 110.688 89.0996 135.15 108.549
|
|
||||||
c22.6992 18.1426 60.1299 55.8594 103.335 55.8594c43.4365 0 81.2314 -38.1914 103.335 -55.8594c23.5283 -18.707 130.554 -104.773 135.251 -108.656zM464 -10v253.632v0.00488281c0 1.5791 -0.996094 3.66602 -2.22363 4.6582
|
|
||||||
c-15.8633 12.8232 -108.793 87.5752 -132.366 106.316c-17.5527 14.0195 -49.7168 45.3887 -73.4102 45.3887c-23.6016 0 -55.2451 -30.8799 -73.4102 -45.3887c-23.5713 -18.7393 -116.494 -93.4795 -132.364 -106.293
|
|
||||||
c-1.40918 -1.13965 -2.22559 -2.85254 -2.22559 -4.66504v-253.653c0 -3.31152 2.68848 -6 6 -6h404c3.31152 0 6 2.68848 6 6zM432.009 177.704c4.24902 -5.15918 3.46484 -12.7949 -1.74512 -16.9814c-28.9746 -23.2822 -59.2734 -47.5967 -70.9287 -56.8623
|
|
||||||
c-22.6992 -18.1436 -60.1299 -55.8604 -103.335 -55.8604c-43.4521 0 -81.2871 38.2373 -103.335 55.8604c-11.2793 8.9668 -41.7441 33.4131 -70.9268 56.8643c-5.20996 4.1875 -5.99316 11.8223 -1.74512 16.9814l15.2578 18.5283
|
|
||||||
c4.17773 5.07227 11.6572 5.84277 16.7793 1.72559c28.6182 -23.001 58.5654 -47.0352 70.5596 -56.5713c17.5527 -14.0195 49.7168 -45.3887 73.4102 -45.3887c23.6016 0 55.2461 30.8799 73.4102 45.3887c11.9941 9.53516 41.9434 33.5703 70.5625 56.5684
|
|
||||||
c5.12207 4.11621 12.6016 3.3457 16.7783 -1.72656z" />
|
|
||||||
<glyph glyph-name="address-book" unicode="" horiz-adv-x="448"
|
|
||||||
d="M436 288h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48
|
|
||||||
h320c26.5 0 48 -21.5 48 -48v-48h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM368 -16v416h-320v-416h320zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM118.4 64
|
|
||||||
c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002
|
|
||||||
h-179.199z" />
|
|
||||||
<glyph glyph-name="address-card" unicode="" horiz-adv-x="576"
|
|
||||||
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v352h-480v-352h480zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z
|
|
||||||
M118.4 64c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002
|
|
||||||
c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199zM360 128c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 192c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
|
|
||||||
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 256c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112z" />
|
|
||||||
<glyph glyph-name="user-circle" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 344c53 0 96 -43 96 -96s-43 -96 -96 -96s-96 43 -96 96s43 96 96 96zM248 200c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
|
|
||||||
c49.7002 0 95.0996 18.2998 130.1 48.4004c-14.8994 23 -40.3994 38.5 -69.5996 39.5c-20.7998 -6.5 -40.5996 -9.60059 -60.5 -9.60059s-39.7002 3.2002 -60.5 9.60059c-29.2002 -0.900391 -54.7002 -16.5 -69.5996 -39.5c35 -30.1006 80.3994 -48.4004 130.1 -48.4004z
|
|
||||||
M410.7 76.0996c23.3994 32.7002 37.2998 72.7002 37.2998 115.9c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -43.2002 13.9004 -83.2002 37.2998 -115.9c24.5 31.4004 62.2002 51.9004 105.101 51.9004c10.1992 0 26.0996 -9.59961 57.5996 -9.59961
|
|
||||||
c31.5996 0 47.4004 9.59961 57.5996 9.59961c43 0 80.7002 -20.5 105.101 -51.9004z" />
|
|
||||||
<glyph glyph-name="id-badge" unicode="" horiz-adv-x="384"
|
|
||||||
d="M336 448c26.5 0 48 -21.5 48 -48v-416c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h288zM336 -16v416h-288v-416h288zM144 336c-8.7998 0 -16 7.2002 -16 16s7.2002 16 16 16h96c8.7998 0 16 -7.2002 16 -16s-7.2002 -16 -16 -16
|
|
||||||
h-96zM192 160c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM102.4 32c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8
|
|
||||||
c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199z" />
|
|
||||||
<glyph glyph-name="id-card" unicode="" horiz-adv-x="576"
|
|
||||||
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v288h-480v-288h32.7998c-1 4.5 -0.799805 -3.59961 -0.799805 22.4004c0 31.7998 30.0996 57.5996 67.2002 57.5996
|
|
||||||
c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996c0 -26 0.0996094 -17.9004 -0.799805 -22.4004h224.8zM360 96c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16
|
|
||||||
c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 160c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 224c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
|
|
||||||
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM192 128c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z" />
|
|
||||||
<glyph glyph-name="window-maximize" unicode=""
|
|
||||||
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v234h-416v-234c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="window-minimize" unicode=""
|
|
||||||
d="M480 -32h-448c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32h448c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
|
|
||||||
<glyph glyph-name="window-restore" unicode=""
|
|
||||||
d="M464 448c26.5 0 48 -21.5 48 -48v-320c0 -26.5 -21.5 -48 -48 -48h-48v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v320c0 26.5 21.5 48 48 48h48v48c0 26.5 21.5 48 48 48h320zM368 -16v208h-320v-208h320zM464 80v320h-320v-48h224
|
|
||||||
c26.5 0 48 -21.5 48 -48v-224h48z" />
|
|
||||||
<glyph glyph-name="snowflake" unicode="" horiz-adv-x="448"
|
|
||||||
d="M440.1 92.7998c7.60059 -4.39941 10.1006 -14.2002 5.5 -21.7002l-7.89941 -13.8994c-4.40039 -7.7002 -14 -10.2998 -21.5 -5.90039l-39.2002 23l9.09961 -34.7002c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.5996l-15.2002 -4.09961
|
|
||||||
c-8.39941 -2.30078 -17.0996 2.7998 -19.2998 11.2998l-21.2998 81l-71.9004 42.2002v-84.5l58.2998 -59.3008c6.10059 -6.19922 6.10059 -16.3994 0 -22.5996l-11.0996 -11.2998c-6.09961 -6.2002 -16.0996 -6.2002 -22.2002 0l-24.8994 25.3994v-46.0996
|
|
||||||
c0 -8.7998 -7 -16 -15.7002 -16h-15.7002c-8.7002 0 -15.7002 7.2002 -15.7002 16v45.9004l-24.8994 -25.4004c-6.10059 -6.2002 -16.1006 -6.2002 -22.2002 0l-11.1006 11.2998c-6.09961 6.2002 -6.09961 16.4004 0 22.6006l58.3008 59.2998v84.5l-71.9004 -42.2002
|
|
||||||
l-21.2998 -81c-2.2998 -8.5 -10.9004 -13.5996 -19.2998 -11.2998l-15.2002 4.09961c-8.40039 2.2998 -13.2998 11.1006 -11.1006 19.6006l9.10059 34.6992l-39.2002 -23c-7.5 -4.39941 -17.2002 -1.7998 -21.5 5.90039l-7.90039 13.9004
|
|
||||||
c-4.2998 7.69922 -1.69922 17.5 5.80078 21.8994l39.1992 23l-34.0996 9.2998c-8.40039 2.30078 -13.2998 11.1006 -11.0996 19.6006l4.09961 15.5c2.2998 8.5 10.9004 13.5996 19.2998 11.2998l79.7002 -21.7002l71.9004 42.2002l-71.9004 42.2002l-79.7002 -21.7002
|
|
||||||
c-8.39941 -2.2998 -17.0996 2.7998 -19.2998 11.2998l-4.09961 15.5c-2.30078 8.5 2.69922 17.2998 11.0996 19.6006l34.0996 9.09961l-39.1992 23c-7.60059 4.5 -10.1006 14.2002 -5.80078 21.9004l7.90039 13.8994c4.40039 7.7002 14 10.2998 21.5 5.90039l39.2002 -23
|
|
||||||
l-9.10059 34.7002c-2.2998 8.5 2.7002 17.2998 11.1006 19.5996l15.2002 4.09961c8.39941 2.30078 17.0996 -2.7998 19.2998 -11.2998l21.2998 -81l71.9004 -42.2002v84.5l-58.3008 59.3008c-6.09961 6.19922 -6.09961 16.3994 0 22.5996l11.5 11.2998
|
|
||||||
c6.10059 6.2002 16.1006 6.2002 22.2002 0l24.9004 -25.3994v46.0996c0 8.7998 7 16 15.7002 16h15.6992c8.7002 0 15.7002 -7.2002 15.7002 -16v-45.9004l24.9004 25.4004c6.09961 6.2002 16.0996 6.2002 22.2002 0l11.0996 -11.2998
|
|
||||||
c6.09961 -6.2002 6.09961 -16.4004 0 -22.6006l-58.2998 -59.2998v-84.5l71.8994 42.2002l21.3008 81c2.2998 8.5 10.8994 13.5996 19.2998 11.2998l15.2002 -4.09961c8.39941 -2.2998 13.2998 -11.1006 11.0996 -19.6006l-9.09961 -34.6992l39.1992 23
|
|
||||||
c7.5 4.39941 17.2002 1.7998 21.5 -5.90039l7.90039 -13.9004c4.2998 -7.69922 1.7002 -17.5 -5.7998 -21.8994l-39.2002 -23l34.0996 -9.2998c8.40039 -2.30078 13.3008 -11.1006 11.1006 -19.6006l-4.10059 -15.5c-2.2998 -8.5 -10.8994 -13.5996 -19.2998 -11.2998
|
|
||||||
l-79.7002 21.7002l-71.8994 -42.2002l71.7998 -42.2002l79.7002 21.7002c8.39941 2.2998 17.0996 -2.7998 19.2998 -11.2998l4.09961 -15.5c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.6006l-34.0996 -9.2998z" />
|
|
||||||
<glyph glyph-name="trash-alt" unicode="" horiz-adv-x="448"
|
|
||||||
d="M268 32c-6.62402 0 -12 5.37598 -12 12v216c0 6.62402 5.37598 12 12 12h24c6.62402 0 12 -5.37598 12 -12v-216c0 -6.62402 -5.37598 -12 -12 -12h-24zM432 368c8.83203 0 16 -7.16797 16 -16v-16c0 -8.83203 -7.16797 -16 -16 -16h-16v-336
|
|
||||||
c0 -26.4961 -21.5039 -48 -48 -48h-288c-26.4961 0 -48 21.5039 -48 48v336h-16c-8.83203 0 -16 7.16797 -16 16v16c0 8.83203 7.16797 16 16 16h82.4102l34.0195 56.7002c7.71875 12.8613 26.1572 23.2998 41.1572 23.2998h0.00292969h100.82h0.0224609
|
|
||||||
c15 0 33.4385 -10.4385 41.1572 -23.2998l34 -56.7002h82.4102zM171.84 397.09l-17.4502 -29.0898h139.221l-17.46 29.0898c-0.96582 1.60645 -3.26953 2.91016 -5.14355 2.91016h-0.00683594h-94h-0.0166016c-1.87402 0 -4.17871 -1.30371 -5.14355 -2.91016zM368 -16v336
|
|
||||||
h-288v-336h288zM156 32c-6.62402 0 -12 5.37598 -12 12v216c0 6.62402 5.37598 12 12 12h24c6.62402 0 12 -5.37598 12 -12v-216c0 -6.62402 -5.37598 -12 -12 -12h-24z" />
|
|
||||||
<glyph glyph-name="images" unicode="" horiz-adv-x="576"
|
|
||||||
d="M480 32v-16c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256c0 26.5098 21.4902 48 48 48h16v-48h-10c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v10h48zM522 368h-372
|
|
||||||
c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v244c0 3.31152 -2.68848 6 -6 6zM528 416c26.5098 0 48 -21.4902 48 -48v-256c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256
|
|
||||||
c0 26.5098 21.4902 48 48 48h384zM264 304c0 -22.0908 -17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40s40 -17.9092 40 -40zM192 208l39.5146 39.5146c4.68652 4.68652 12.2842 4.68652 16.9717 0l39.5137 -39.5146l103.515 103.515
|
|
||||||
c4.68652 4.68652 12.2842 4.68652 16.9717 0l71.5137 -71.5146v-80h-288v48z" />
|
|
||||||
<glyph glyph-name="clipboard" unicode="" horiz-adv-x="384"
|
|
||||||
d="M336 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h80c0 35.2998 28.7002 64 64 64s64 -28.7002 64 -64h80zM192 408c-13.2998 0 -24 -10.7002 -24 -24s10.7002 -24 24 -24s24 10.7002 24 24
|
|
||||||
s-10.7002 24 -24 24zM336 -10v340c0 3.2998 -2.7002 6 -6 6h-42v-36c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v36h-42c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h276c3.2998 0 6 2.7002 6 6z" />
|
|
||||||
<glyph glyph-name="arrow-alt-circle-down" unicode=""
|
|
||||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM224 308c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-116
|
|
||||||
h67c10.7002 0 16.0996 -12.9004 8.5 -20.5l-99 -99c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-99 99c-7.5 7.59961 -2.2002 20.5 8.5 20.5h67v116z" />
|
|
||||||
<glyph glyph-name="arrow-alt-circle-left" unicode=""
|
|
||||||
d="M8 192c0 137 111 248 248 248s248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248zM456 192c0 110.5 -89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200zM384 212v-40c0 -6.59961 -5.40039 -12 -12 -12h-116v-67
|
|
||||||
c0 -10.7002 -12.9004 -16 -20.5 -8.5l-99 99c-4.7002 4.7002 -4.7002 12.2998 0 17l99 99c7.59961 7.59961 20.5 2.2002 20.5 -8.5v-67h116c6.59961 0 12 -5.40039 12 -12z" />
|
|
||||||
<glyph glyph-name="arrow-alt-circle-right" unicode=""
|
|
||||||
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM128 172v40c0 6.59961 5.40039 12 12 12h116v67
|
|
||||||
c0 10.7002 12.9004 16 20.5 8.5l99 -99c4.7002 -4.7002 4.7002 -12.2998 0 -17l-99 -99c-7.59961 -7.59961 -20.5 -2.2002 -20.5 8.5v67h-116c-6.59961 0 -12 5.40039 -12 12z" />
|
|
||||||
<glyph glyph-name="arrow-alt-circle-up" unicode=""
|
|
||||||
d="M256 -56c-137 0 -248 111 -248 248s111 248 248 248s248 -111 248 -248s-111 -248 -248 -248zM256 392c-110.5 0 -200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200zM276 64h-40c-6.59961 0 -12 5.40039 -12 12v116h-67
|
|
||||||
c-10.7002 0 -16 12.9004 -8.5 20.5l99 99c4.7002 4.7002 12.2998 4.7002 17 0l99 -99c7.59961 -7.59961 2.2002 -20.5 -8.5 -20.5h-67v-116c0 -6.59961 -5.40039 -12 -12 -12z" />
|
|
||||||
<glyph glyph-name="gem" unicode="" horiz-adv-x="576"
|
|
||||||
d="M464 448c4.09961 0 7.7998 -2 10.0996 -5.40039l99.9004 -147.199c2.90039 -4.40039 2.59961 -10.1006 -0.700195 -14.2002l-276 -340.8c-4.7998 -5.90039 -13.7998 -5.90039 -18.5996 0l-276 340.8c-3.2998 4 -3.60059 9.7998 -0.700195 14.2002l100 147.199
|
|
||||||
c2.2002 3.40039 6 5.40039 10 5.40039h352zM444.7 400h-56.7998l51.6992 -96h68.4004zM242.6 400l-51.5996 -96h194l-51.7002 96h-90.7002zM131.3 400l-63.2998 -96h68.4004l51.6992 96h-56.7998zM88.2998 256l119.7 -160l-68.2998 160h-51.4004zM191.2 256l96.7998 -243.3
|
|
||||||
l96.7998 243.3h-193.6zM368 96l119.6 160h-51.3994z" />
|
|
||||||
<glyph glyph-name="money-bill-alt" unicode="" horiz-adv-x="640"
|
|
||||||
d="M320 304c53.0195 0 96 -50.1396 96 -112c0 -61.8701 -43 -112 -96 -112c-53.0195 0 -96 50.1504 -96 112c0 61.8604 42.9805 112 96 112zM360 136v16c0 4.41992 -3.58008 8 -8 8h-16v88c0 4.41992 -3.58008 8 -8 8h-13.5801h-0.000976562
|
|
||||||
c-4.01074 0 -9.97266 -1.80566 -13.3086 -4.03027l-15.3301 -10.2197c-1.96777 -1.30957 -3.56445 -4.29004 -3.56445 -6.65332c0 -1.33691 0.601562 -3.32422 1.34375 -4.43652l8.88086 -13.3105c1.30859 -1.9668 4.29004 -3.56445 6.65332 -3.56445
|
|
||||||
c1.33691 0 3.32422 0.602539 4.43652 1.34473l0.469727 0.310547v-55.4404h-16c-4.41992 0 -8 -3.58008 -8 -8v-16c0 -4.41992 3.58008 -8 8 -8h64c4.41992 0 8 3.58008 8 8zM608 384c17.6699 0 32 -14.3301 32 -32v-320c0 -17.6699 -14.3301 -32 -32 -32h-576
|
|
||||||
c-17.6699 0 -32 14.3301 -32 32v320c0 17.6699 14.3301 32 32 32h576zM592 112v160c-35.3496 0 -64 28.6504 -64 64h-416c0 -35.3496 -28.6504 -64 -64 -64v-160c35.3496 0 64 -28.6504 64 -64h416c0 35.3496 28.6504 64 64 64z" />
|
|
||||||
<glyph glyph-name="window-close" unicode=""
|
|
||||||
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v340c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z
|
|
||||||
M356.5 253.4l-61.4004 -61.4004l61.4004 -61.4004c4.59961 -4.59961 4.59961 -12.0996 0 -16.7998l-22.2998 -22.2998c-4.60059 -4.59961 -12.1006 -4.59961 -16.7998 0l-61.4004 61.4004l-61.4004 -61.4004c-4.59961 -4.59961 -12.0996 -4.59961 -16.7998 0
|
|
||||||
l-22.2998 22.2998c-4.59961 4.60059 -4.59961 12.1006 0 16.7998l61.4004 61.4004l-61.4004 61.4004c-4.59961 4.59961 -4.59961 12.0996 0 16.7998l22.2998 22.2998c4.60059 4.59961 12.1006 4.59961 16.7998 0l61.4004 -61.4004l61.4004 61.4004
|
|
||||||
c4.59961 4.59961 12.0996 4.59961 16.7998 0l22.2998 -22.2998c4.7002 -4.60059 4.7002 -12.1006 0 -16.7998z" />
|
|
||||||
<glyph glyph-name="comment-dots" unicode=""
|
|
||||||
d="M144 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM256 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM368 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
|
||||||
s-32 14.2998 -32 32s14.2998 32 32 32zM256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5
|
|
||||||
c-3.80078 8.7998 -2 19 4.59961 26c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160
|
|
||||||
c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
|
|
||||||
<glyph glyph-name="smile-wink" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM365.8 138.4c10.2002 -8.5 11.6006 -23.6006 3.10059 -33.8008
|
|
||||||
c-30 -36 -74.1006 -56.5996 -120.9 -56.5996s-90.9004 20.5996 -120.9 56.5996c-8.39941 10.2002 -7.09961 25.3008 3.10059 33.8008c10.0996 8.39941 25.2998 7.09961 33.7998 -3.10059c20.7998 -25.0996 51.5 -39.3994 84 -39.3994s63.2002 14.3994 84 39.3994
|
|
||||||
c8.5 10.2002 23.5996 11.6006 33.7998 3.10059zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 268c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008l-9.5 8.5
|
|
||||||
c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996z" />
|
|
||||||
<glyph glyph-name="angry" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 136c33.5996 0 65.2002 -14.7998 86.7998 -40.5996
|
|
||||||
c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008c-10.6006 -8.89941 -25.7002 -6.69922 -33.7998 3c-24.8008 29.7002 -75 29.7002 -99.8008 0c-8.5 -10.1992 -23.5996 -11.5 -33.7998 -3s-11.5996 23.6006 -3.09961 33.8008
|
|
||||||
c21.5996 25.7998 53.2002 40.5996 86.7998 40.5996zM200 208c0 -17.7002 -14.2998 -32.0996 -32 -32.0996s-32 14.2998 -32 32c0 6.19922 2.2002 11.6992 5.2998 16.5996l-28.2002 8.5c-12.6992 3.7998 -19.8994 17.2002 -16.0996 29.9004
|
|
||||||
c3.7998 12.6992 17.0996 20 29.9004 16.0996l80 -24c12.6992 -3.7998 19.8994 -17.2002 16.0996 -29.9004c-3.09961 -10.3994 -12.7002 -17.0996 -23 -17.0996zM399 262.9c3.7998 -12.7002 -3.40039 -26.1006 -16.0996 -29.8008l-28.2002 -8.5
|
|
||||||
c3.09961 -4.89941 5.2998 -10.3994 5.2998 -16.5996c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32c-10.2998 0 -19.9004 6.7002 -23 17.0996c-3.7998 12.7002 3.40039 26.1006 16.0996 29.9004l80 24c12.8008 3.7998 26.1006 -3.40039 29.9004 -16.0996z" />
|
|
||||||
<glyph glyph-name="dizzy" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM214.2 209.9
|
|
||||||
c-7.90039 -7.90039 -20.5 -7.90039 -28.4004 -0.200195l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998
|
|
||||||
c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.9004c7.7998 7.7998 20.5 7.7998 28.2998 0s7.7998 -20.5 0 -28.2998l-17.9004 -17.9004l17.9004 -17.7998c7.7998 -7.7998 7.7998 -20.5 0 -28.2998zM374.2 302.1
|
|
||||||
c7.7002 -7.7998 7.7002 -20.3994 0 -28.1992l-17.9004 -17.9004l17.7998 -18c7.80078 -7.7998 7.80078 -20.5 0 -28.2998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0
|
|
||||||
c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.7998c7.7998 7.80078 20.5 7.80078 28.2998 0zM248 176
|
|
||||||
c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64s-64 28.7002 -64 64s28.7002 64 64 64z" />
|
|
||||||
<glyph glyph-name="flushed" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM344 304c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80
|
|
||||||
s-80 35.7998 -80 80s35.7998 80 80 80zM344 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM344 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM232 224c0 -44.2002 -35.7998 -80 -80 -80
|
|
||||||
s-80 35.7998 -80 80s35.7998 80 80 80s80 -35.7998 80 -80zM152 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM152 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM312 104
|
|
||||||
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
|
|
||||||
<glyph glyph-name="frown-open" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32
|
|
||||||
s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 160c35.5996 0 88.7998 -21.2998 95.7998 -61.2002c2 -11.7998 -9.09961 -21.5996 -20.5 -18.0996
|
|
||||||
c-31.2002 9.59961 -59.3994 15.2998 -75.2998 15.2998s-44.0996 -5.7002 -75.2998 -15.2998c-11.5 -3.40039 -22.5 6.2998 -20.5 18.0996c7 39.9004 60.2002 61.2002 95.7998 61.2002z" />
|
|
||||||
<glyph glyph-name="grimace" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
|
||||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM344 192c26.5 0 48 -21.5 48 -48v-32c0 -26.5 -21.5 -48 -48 -48h-192c-26.5 0 -48 21.5 -48 48v32c0 26.5 21.5 48 48 48
|
|
||||||
h192zM176 96v24h-40v-8c0 -8.7998 7.2002 -16 16 -16h24zM176 136v24h-24c-8.7998 0 -16 -7.2002 -16 -16v-8h40zM240 96v24h-48v-24h48zM240 136v24h-48v-24h48zM304 96v24h-48v-24h48zM304 136v24h-48v-24h48zM360 112v8h-40v-24h24c8.7998 0 16 7.2002 16 16zM360 136v8
|
|
||||||
c0 8.7998 -7.2002 16 -16 16h-24v-24h40z" />
|
|
||||||
<glyph glyph-name="grin" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
|
||||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
|
||||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
|
|
||||||
<glyph glyph-name="grin-alt" unicode="" horiz-adv-x="496"
|
|
||||||
d="M200.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56
|
|
||||||
c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM328.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0
|
|
||||||
c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200
|
|
||||||
s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006
|
|
||||||
s79.7002 4.7998 105.6 13.1006z" />
|
|
||||||
<glyph glyph-name="grin-beam" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
|
||||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM117.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
|
||||||
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996
|
|
||||||
l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002zM277.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998
|
|
||||||
c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002z" />
|
|
||||||
<glyph glyph-name="grin-beam-sweat" unicode="" horiz-adv-x="496"
|
|
||||||
d="M440 288c-29.5 0 -53.2998 26.2998 -53.2998 58.7002c0 25 31.7002 75.5 46.2002 97.2998c3.5 5.2998 10.5996 5.2998 14.1992 0c14.5 -21.7998 46.2002 -72.2998 46.2002 -97.2998c0 -32.4004 -23.7998 -58.7002 -53.2998 -58.7002zM248 48
|
|
||||||
c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM378.3 216.3
|
|
||||||
c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
|
||||||
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM483.6 269.2c8 -24.2998 12.4004 -50.2002 12.4004 -77.2002c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248
|
|
||||||
c45.7002 0 88.4004 -12.5996 125.2 -34.2002c-10.9004 -21.5996 -15.5 -36.2002 -17.2002 -45.7002c-31.2002 20.1006 -68.2002 31.9004 -108 31.9004c-110.3 0 -200 -89.7002 -200 -200s89.7002 -200 200 -200s200 89.7002 200 200
|
|
||||||
c0 22.5 -3.90039 44.0996 -10.7998 64.2998c0.399414 0 21.7998 -2.7998 46.3994 12.9004zM168 258.6c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
|
||||||
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
|
|
||||||
<glyph glyph-name="grin-hearts" unicode="" horiz-adv-x="496"
|
|
||||||
d="M353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM200.8 192.3
|
|
||||||
l-70.2002 18.1006c-20.3994 5.2998 -31.8994 27 -24.1992 47.1992c6.69922 17.7002 26.6992 26.7002 44.8994 22l7.10059 -1.89941l2 7.09961c5.09961 18.1006 22.8994 30.9004 41.5 27.9004c21.3994 -3.40039 34.3994 -24.2002 28.7998 -44.5l-19.4004 -69.9004
|
|
||||||
c-1.2998 -4.5 -6 -7.2002 -10.5 -6zM389.6 257.6c7.7002 -20.1992 -3.7998 -41.7998 -24.1992 -47.0996l-70.2002 -18.2002c-4.60059 -1.2002 -9.2998 1.5 -10.5 6l-19.4004 69.9004c-5.59961 20.2998 7.40039 41.0996 28.7998 44.5c18.7002 3 36.5 -9.7998 41.5 -27.9004
|
|
||||||
l2 -7.09961l7.10059 1.89941c18.2002 4.7002 38.2002 -4.39941 44.8994 -22zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200
|
|
||||||
s89.7002 -200 200 -200z" />
|
|
||||||
<glyph glyph-name="grin-squint" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
|
||||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM118.9 184.2c-3.80078 4.39941 -3.90039 11 -0.100586 15.5l33.6006 40.2998
|
|
||||||
l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5c3.89941 4.40039 10.1992 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5zM361.8 181.7
|
|
||||||
l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5.10059 2.90039 11.5 1.90039 15.2998 -2.5c3.80078 -4.5 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5
|
|
||||||
c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5z" />
|
|
||||||
<glyph glyph-name="grin-squint-tears" unicode=""
|
|
||||||
d="M117.1 63.9004c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998
|
|
||||||
c16.8994 16.9004 75.0996 26.9004 100.899 30.6006zM75.9004 105.6c-19.6006 -3.89941 -35.1006 -8.09961 -47.3008 -12.1992c-39.2998 90.5996 -22.0996 199.899 52 274c48.5 48.3994 111.9 72.5996 175.4 72.5996c38.9004 0 77.7998 -9.2002 113.2 -27.4004
|
|
||||||
c-4 -12.1992 -8.2002 -28 -12 -48.2998c-30.4004 17.9004 -65 27.7002 -101.2 27.7002c-53.4004 0 -103.6 -20.7998 -141.4 -58.5996c-61.5996 -61.5 -74.2998 -153.4 -38.6992 -227.801zM428.2 293.2c20.2998 3.89941 36.2002 8 48.5 12
|
|
||||||
c47.8994 -93.2002 32.8994 -210.5 -45.2002 -288.601c-48.5 -48.3994 -111.9 -72.5996 -175.4 -72.5996c-33.6992 0 -67.2998 7 -98.6992 20.5996c4.19922 12.2002 8.2998 27.7002 12.1992 47.2002c26.6006 -12.7998 55.9004 -19.7998 86.4004 -19.7998
|
|
||||||
c53.4004 0 103.6 20.7998 141.4 58.5996c65.6992 65.7002 75.7998 166 30.7998 242.601zM394.9 320.1c-6.30078 -0.899414 -11.7002 4.5 -10.9004 10.9004c3.7002 25.7998 13.7002 84 30.5996 100.9c22 21.8994 57.9004 21.5 80.3008 -0.900391
|
|
||||||
c22.3994 -22.4004 22.7998 -58.4004 0.899414 -80.2998c-16.8994 -16.9004 -75.0996 -26.9004 -100.899 -30.6006zM207.9 211.8c3 -3 4.19922 -7.2998 3.19922 -11.5l-22.5996 -90.5c-1.40039 -5.39941 -6.2002 -9.09961 -11.7002 -9.09961h-0.899414
|
|
||||||
c-5.80078 0.5 -10.5 5.09961 -11 10.8994l-4.80078 52.3008l-52.2998 4.7998c-5.7998 0.5 -10.3994 5.2002 -10.8994 11c-0.400391 5.89941 3.39941 11.2002 9.09961 12.5996l90.5 22.7002c4.2002 1 8.40039 -0.200195 11.4004 -3.2002zM247.6 236.9
|
|
||||||
c-0.0996094 0 -6.39941 -1.80078 -11.3994 3.19922c-3 3 -4.2002 7.30078 -3.2002 11.4004l22.5996 90.5c1.40039 5.7002 7 9.2002 12.6006 9.09961c5.7998 -0.5 10.5 -5.09961 11 -10.8994l4.7998 -52.2998l52.2998 -4.80078c5.7998 -0.5 10.4004 -5.19922 10.9004 -11
|
|
||||||
c0.399414 -5.89941 -3.40039 -11.1992 -9.10059 -12.5996zM299.6 148.4c29.1006 29.0996 53 59.5996 65.3008 83.7998c4.89941 9.2998 17.5996 9.89941 23.3994 1.7002c27.7002 -38.9004 6.10059 -106.9 -30.5996 -143.7s-104.8 -58.2998 -143.7 -30.6006
|
|
||||||
c-8.2998 5.90039 -7.5 18.6006 1.7002 23.4004c24.2002 12.5 54.7998 36.2998 83.8994 65.4004z" />
|
|
||||||
<glyph glyph-name="grin-stars" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
|
||||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM125.7 200.9l6.09961 34.8994l-25.3994 24.6006
|
|
||||||
c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006l34.9004 -5c6.19922 -1 8.7998 -8.69922 4.2998 -13.1992l-25.4004 -24.6006l6 -34.8994c1 -6.2002 -5.39941 -11 -11 -7.90039
|
|
||||||
l-31.2998 16.2998l-31.2998 -16.2998c-5.60059 -3.09961 -12 1.7002 -11 7.90039zM385.4 273.6c6.19922 -1 8.89941 -8.59961 4.39941 -13.1992l-25.3994 -24.6006l6 -34.8994c1 -6.2002 -5.40039 -11 -11 -7.90039l-31.3008 16.2998l-31.2998 -16.2998
|
|
||||||
c-5.59961 -3.09961 -12 1.7002 -11 7.90039l6 34.8994l-25.3994 24.6006c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006z" />
|
|
||||||
<glyph glyph-name="grin-tears" unicode="" horiz-adv-x="640"
|
|
||||||
d="M117.1 191.9c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998c16.8994 16.9004 75.0996 26.9004 100.899 30.6006
|
|
||||||
zM623.8 161.3c21.9004 -21.8994 21.5 -57.8994 -0.799805 -80.2002c-22.4004 -22.3994 -58.4004 -22.7998 -80.2998 -0.899414c-16.9004 16.8994 -26.9004 75.0996 -30.6006 100.899c-0.899414 6.30078 4.5 11.7002 10.8008 10.8008
|
|
||||||
c25.7998 -3.7002 84 -13.7002 100.899 -30.6006zM497.2 99.5996c12.3994 -37.2998 25.0996 -43.7998 28.2998 -46.5c-44.5996 -65.7998 -120 -109.1 -205.5 -109.1s-160.9 43.2998 -205.5 109.1c3.09961 2.60059 15.7998 9.10059 28.2998 46.5
|
|
||||||
c33.4004 -63.8994 100.3 -107.6 177.2 -107.6s143.8 43.7002 177.2 107.6zM122.7 223.5c-2.40039 0.299805 -5 2.5 -49.5 -6.90039c12.3994 125.4 118.1 223.4 246.8 223.4s234.4 -98 246.8 -223.5c-44.2998 9.40039 -47.3994 7.2002 -49.5 7
|
|
||||||
c-15.2002 95.2998 -97.7998 168.5 -197.3 168.5s-182.1 -73.2002 -197.3 -168.5zM320 48c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996
|
|
||||||
c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM450.3 216.3c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17
|
|
||||||
c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM240 258.6
|
|
||||||
c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
|
|
||||||
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
|
|
||||||
<glyph glyph-name="grin-tongue" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
|
|
||||||
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
|
|
||||||
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
|
|
||||||
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32
|
|
||||||
s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
|
||||||
<glyph glyph-name="grin-tongue-squint" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
|
|
||||||
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
|
|
||||||
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
|
|
||||||
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998
|
|
||||||
l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 3 11.5 1.90039 15.2998 -2.5zM214.2 250.3
|
|
||||||
c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5
|
|
||||||
c3.89941 4.5 10.2998 5.5 15.2998 2.5z" />
|
|
||||||
<glyph glyph-name="grin-tongue-wink" unicode="" horiz-adv-x="496"
|
|
||||||
d="M152 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
|
|
||||||
c-3.7998 -3.39941 -9.2998 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM328 320c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80s-80 35.7998 -80 80s35.7998 80 80 80zM328 192
|
|
||||||
c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM328 264c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248z
|
|
||||||
M312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998
|
|
||||||
c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3
|
|
||||||
c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998
|
|
||||||
c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998z" />
|
|
||||||
<glyph glyph-name="grin-wink" unicode="" horiz-adv-x="496"
|
|
||||||
d="M328 268c25.6904 0 55.8799 -16.9199 59.8701 -42.1201c1.72949 -11.0898 -11.3506 -18.2695 -19.8301 -10.8398l-9.5498 8.47949c-14.8105 13.1904 -46.1602 13.1904 -60.9707 0l-9.5498 -8.47949c-8.33008 -7.40039 -21.5801 -0.379883 -19.8301 10.8398
|
|
||||||
c3.98047 25.2002 34.1699 42.1201 59.8604 42.1201zM168 208c-17.6699 0 -32 14.3301 -32 32s14.3301 32 32 32s32 -14.3301 32 -32s-14.3301 -32 -32 -32zM353.55 143.36c10.04 3.13965 19.3906 -5.4502 17.71 -15.3408
|
|
||||||
c-7.92969 -47.1494 -71.3193 -80.0195 -123.26 -80.0195s-115.33 32.8701 -123.26 80.0195c-1.69043 9.9707 7.76953 18.4707 17.71 15.3408c25.9297 -8.31055 64.3994 -13.0605 105.55 -13.0605s79.6201 4.75977 105.55 13.0605zM248 440c136.97 0 248 -111.03 248 -248
|
|
||||||
s-111.03 -248 -248 -248s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
|
||||||
<glyph glyph-name="kiss" unicode="" horiz-adv-x="496"
|
|
||||||
d="M168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
|
|
||||||
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
|
|
||||||
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM248 440c137 0 248 -111 248 -248
|
|
||||||
s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z
|
|
||||||
" />
|
|
||||||
<glyph glyph-name="kiss-beam" unicode="" horiz-adv-x="496"
|
|
||||||
d="M168 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
|
|
||||||
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
|
|
||||||
c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
|
|
||||||
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
|
|
||||||
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM328 296
|
|
||||||
c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
|
|
||||||
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
|
|
||||||
<glyph glyph-name="kiss-wink-heart" unicode="" horiz-adv-x="504"
|
|
||||||
d="M304 139.5c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002
|
|
||||||
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002
|
|
||||||
c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM374.5 223c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-2.5 -2.2998 -7.90039 -4.7002 -13.7002 -1.59961c-4.39941 2.39941 -6.89941 7.39941 -6.09961 12.3994
|
|
||||||
c3.89941 25.2002 34.2002 42.1006 59.7998 42.1006s55.7998 -16.9004 59.7998 -42.1006c0.799805 -5 -1.7002 -10 -6.09961 -12.3994c-4.40039 -2.40039 -9.90039 -1.7002 -13.7002 1.59961zM136 239.5c0 17.7002 14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
|
||||||
s-32 14.2998 -32 32zM501.1 45.5c9.2002 -23.9004 -4.39941 -49.4004 -28.5 -55.7002l-83 -21.5c-5.39941 -1.39941 -10.8994 1.7998 -12.3994 7.10059l-22.9004 82.5996c-6.59961 24 8.7998 48.5996 34 52.5996c22 3.5 43.1006 -11.5996 49 -33l2.2998 -8.39941
|
|
||||||
l8.40039 2.2002c21.5996 5.59961 45.0996 -5.10059 53.0996 -25.9004zM334 11.7002c17.7002 -64 10.9004 -39.5 13.4004 -46.7998c-30.5 -13.4004 -64 -20.9004 -99.4004 -20.9004c-137 0 -248 111 -248 248s111 248 248 248s248 -111 247.9 -248
|
|
||||||
c0 -31.7998 -6.2002 -62.0996 -17.1006 -90c-6 1.5 -12.2002 2.7998 -18.5996 2.90039c-5.60059 9.69922 -13.6006 17.5 -22.6006 23.8994c6.7002 19.9004 10.4004 41.1006 10.4004 63.2002c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200
|
|
||||||
c30.7998 0 59.9004 7.2002 86 19.7002z" />
|
|
||||||
<glyph glyph-name="laugh" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
|
||||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM168 224
|
|
||||||
c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
|
||||||
<glyph glyph-name="laugh-beam" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
|
||||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.700195 -8.5 -10.7998 -11.8994 -14.8994 -4.5
|
|
||||||
l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006c-12.3008 0 -23.8008 -7.90039 -31.5 -21.6006l-9.5 -17c-4.10059 -7.39941 -15.6006 -4.09961 -14.9004 4.5c3.2998 42.1006 32.2002 71.4004 56 71.4004zM127 220.1c-4.2002 -7.39941 -15.7002 -4 -15.0996 4.5
|
|
||||||
c3.2998 42.1006 32.1992 71.4004 56 71.4004c23.7998 0 52.6992 -29.2998 56 -71.4004c0.699219 -8.5 -10.8008 -11.8994 -14.9004 -4.5l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006s-23.7998 -7.90039 -31.5 -21.6006zM362.4 160c8.19922 0 14.5 -7 13.5 -15
|
|
||||||
c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
|
||||||
<glyph glyph-name="laugh-squint" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
|
||||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM343.6 252l33.6006 -40.2998c8.59961 -10.4004 -3.90039 -24.7998 -15.4004 -18l-80 48
|
|
||||||
c-7.7998 4.7002 -7.7998 15.8994 0 20.5996l80 48c11.6006 6.7998 24 -7.7002 15.4004 -18zM134.2 193.7c-11.6006 -6.7998 -24.1006 7.59961 -15.4004 18l33.6006 40.2998l-33.6006 40.2998c-8.59961 10.2998 3.7998 24.9004 15.4004 18l80 -48
|
|
||||||
c7.7998 -4.7002 7.7998 -15.8994 0 -20.5996zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
|
||||||
<glyph glyph-name="laugh-wink" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
|
||||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 284c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008
|
|
||||||
l-9.5 8.5c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996zM168 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z
|
|
||||||
M362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
|
||||||
<glyph glyph-name="meh-blank" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
|
||||||
s-32 14.2998 -32 32s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
|
||||||
<glyph glyph-name="meh-rolling-eyes" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM336 296c39.7998 0 72 -32.2002 72 -72s-32.2002 -72 -72 -72
|
|
||||||
s-72 32.2002 -72 72s32.2002 72 72 72zM336 184c22.0996 0 40 17.9004 40 40c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998
|
|
||||||
c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998c0 -22.0996 17.9004 -40 40 -40zM232 224c0 -39.7998 -32.2002 -72 -72 -72s-72 32.2002 -72 72s32.2002 72 72 72s72 -32.2002 72 -72zM120 224c0 -22.0996 17.9004 -40 40 -40s40 17.9004 40 40
|
|
||||||
c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998zM312 96
|
|
||||||
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
|
|
||||||
<glyph glyph-name="sad-cry" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM392 53.5996c34.5996 35.9004 56 84.7002 56 138.4c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -53.7002 21.4004 -102.4 56 -138.4v114.4
|
|
||||||
c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-151.4c28.5 -15.5996 61.2002 -24.5996 96 -24.5996s67.5 9 96 24.5996v151.4c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-114.4zM205.8 213.5c-5.7998 -3.2002 -11.2002 -0.700195 -13.7002 1.59961l-9.5 8.5
|
|
||||||
c-14.7998 13.2002 -46.1992 13.2002 -61 0l-9.5 -8.5c-3.7998 -3.39941 -9.2998 -4 -13.6992 -1.59961c-4.40039 2.40039 -6.90039 7.40039 -6.10059 12.4004c3.90039 25.1992 34.2002 42.0996 59.7998 42.0996c25.6006 0 55.8008 -16.9004 59.8008 -42.0996
|
|
||||||
c0.799805 -5 -1.7002 -10 -6.10059 -12.4004zM344 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
|
|
||||||
c-3.7998 -3.39941 -9.2002 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM248 176c30.9004 0 56 -28.7002 56 -64s-25.0996 -64 -56 -64s-56 28.7002 -56 64s25.0996 64 56 64z" />
|
|
||||||
<glyph glyph-name="sad-tear" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM256 144c38.0996 0 74 -16.7998 98.5 -46.0996
|
|
||||||
c8.5 -10.2002 7.09961 -25.3008 -3.09961 -33.8008c-10.6006 -8.7998 -25.7002 -6.69922 -33.8008 3.10059c-15.2998 18.2998 -37.7998 28.7998 -61.5996 28.7998c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
|
||||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM162.4 173.2c2.7998 3.7002 8.39941 3.7002 11.1992 0c11.4004 -15.2998 36.4004 -50.6006 36.4004 -68.1006
|
|
||||||
c0 -22.6992 -18.7998 -41.0996 -42 -41.0996s-42 18.4004 -42 41.0996c0 17.5 25 52.8008 36.4004 68.1006z" />
|
|
||||||
<glyph glyph-name="smile-beam" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM332 135.4c8.5 10.1992 23.5996 11.5 33.7998 3.09961
|
|
||||||
c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.2002 8.40039 25.2998 7.09961 33.7998 -3.09961
|
|
||||||
c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004zM136.5 237l-9.5 -17c-1.90039 -3.2002 -5.90039 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
|
|
||||||
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996zM328 296c23.7998 0 52.7002 -29.2998 56 -71.4004
|
|
||||||
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002
|
|
||||||
c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
|
|
||||||
<glyph glyph-name="surprise" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 168c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64
|
|
||||||
s-64 28.7002 -64 64s28.7002 64 64 64zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
|
||||||
<glyph glyph-name="tired" unicode="" horiz-adv-x="496"
|
|
||||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5
|
|
||||||
l-33.6006 -40.2998l33.6006 -40.2998c3.7998 -4.5 3.7002 -11 -0.100586 -15.5c-3.5 -4.10059 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 2.90039 11.5 1.90039 15.2998 -2.5z
|
|
||||||
M220 240c0 -4.2002 -2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7998 -1.60059 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7998 4.5 -3.7002 11 0.100586 15.5
|
|
||||||
c3.7998 4.40039 10.2998 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998zM248 176c45.4004 0 100.9 -38.2998 107.8 -93.2998c1.5 -11.9004 -7 -21.6006 -15.5 -17.9004c-22.7002 9.7002 -56.2998 15.2002 -92.2998 15.2002
|
|
||||||
s-69.5996 -5.5 -92.2998 -15.2002c-8.60059 -3.7002 -17 6.10059 -15.5 17.9004c6.89941 55 62.3994 93.2998 107.8 93.2998z" />
|
|
||||||
</font>
|
|
||||||
</defs></svg>
|
|
||||||
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 876 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 148 KiB |