feat: oma profiili -toiminto + placeholder-siivous + poista fix-skriptit

- Lisätty "Oma profiili" -nappi headeriin (⚙ + nimen klikkaus)
- Profiili-modaali: muokkaa nimi, sähköposti, salasana, allekirjoitukset
- Uusi profile_update API-endpoint (vaatii vain kirjautumisen)
- check_auth palauttaa nyt myös email-kentän
- Siivottu kaikki yrityskohtaiset placeholder-tekstit geneerisiksi
  (cuitunet.fi → yritys.fi, Kauppakatu → Esimerkkikatu, jne.)
- Poistettu väliaikaiset fix_role.php ja fix_saatavuus.php

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 21:38:32 +02:00
parent f6602fb81f
commit f6e11f8426
7 changed files with 178 additions and 133 deletions

40
api.php
View File

@@ -993,6 +993,7 @@ switch ($action) {
'user_id' => $_SESSION['user_id'], 'user_id' => $_SESSION['user_id'],
'username' => $_SESSION['username'], 'username' => $_SESSION['username'],
'nimi' => $_SESSION['nimi'], 'nimi' => $_SESSION['nimi'],
'email' => $u['email'] ?? '',
'role' => $_SESSION['role'], 'role' => $_SESSION['role'],
'companies' => $companyList, 'companies' => $companyList,
'company_id' => $_SESSION['company_id'] ?? '', 'company_id' => $_SESSION['company_id'] ?? '',
@@ -1030,7 +1031,7 @@ switch ($action) {
$html .= '<p><a href="' . $resetUrl . '" style="display:inline-block;background:#0f3460;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;font-weight:600;">Vaihda salasana</a></p>'; $html .= '<p><a href="' . $resetUrl . '" style="display:inline-block;background:#0f3460;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;font-weight:600;">Vaihda salasana</a></p>';
$html .= '<p style="color:#888;font-size:0.9em;">Linkki on voimassa 1 tunnin. Jos et pyytänyt salasanan vaihtoa, voit jättää tämän viestin huomiotta.</p>'; $html .= '<p style="color:#888;font-size:0.9em;">Linkki on voimassa 1 tunnin. Jos et pyytänyt salasanan vaihtoa, voit jättää tämän viestin huomiotta.</p>';
$html .= '</div>'; $html .= '</div>';
sendMail($user['email'], 'Salasanan palautus - CuituNet Intra', $html); sendMail($user['email'], 'Salasanan palautus - Noxus Intra', $html);
} }
echo json_encode(['success' => true, 'message' => 'Jos käyttäjätunnus löytyy ja sillä on sähköposti, palautuslinkki lähetetään.']); echo json_encode(['success' => true, 'message' => 'Jos käyttäjätunnus löytyy ja sillä on sähköposti, palautuslinkki lähetetään.']);
break; break;
@@ -1236,6 +1237,43 @@ switch ($action) {
echo json_encode(['success' => true]); echo json_encode(['success' => true]);
break; break;
// ---------- PROFILE (oma profiili) ----------
case 'profile_update':
requireAuth();
if ($method !== 'POST') break;
$input = json_decode(file_get_contents('php://input'), true);
$userId = $_SESSION['user_id'];
$u = dbGetUser($userId);
if (!$u) {
http_response_code(404);
echo json_encode(['error' => 'Käyttäjää ei löydy']);
break;
}
if (isset($input['nimi'])) $u['nimi'] = trim($input['nimi']);
if (isset($input['email'])) $u['email'] = trim($input['email']);
if (!empty($input['password'])) {
if (strlen($input['password']) < 4) {
http_response_code(400);
echo json_encode(['error' => 'Salasanan pitää olla vähintään 4 merkkiä']);
break;
}
$u['password_hash'] = password_hash($input['password'], PASSWORD_DEFAULT);
}
if (isset($input['signatures']) && is_array($input['signatures'])) {
$sigs = [];
foreach ($input['signatures'] as $mbId => $sig) {
$sigs[(string)$mbId] = (string)$sig;
}
$u['signatures'] = $sigs;
}
dbSaveUser($u);
// Päivitä session nimi
$_SESSION['nimi'] = $u['nimi'];
$safe = $u;
unset($safe['password_hash']);
echo json_encode($safe);
break;
// ---------- CHANGELOG ---------- // ---------- CHANGELOG ----------
case 'changelog': case 'changelog':
requireAuth(); requireAuth();

View File

@@ -1,29 +0,0 @@
<?php
/**
* Näyttää kaikkien käyttäjien roolit ja korjaa admin → superadmin.
* POISTA TÄMÄ TIEDOSTO KÄYTÖN JÄLKEEN!
* Käyttö: https://intra.noxus.fi/fix_role.php
*/
require_once __DIR__ . '/db.php';
header('Content-Type: text/plain; charset=utf-8');
$db = getDb();
echo "=== KÄYTTÄJIEN ROOLIT ===\n\n";
$result = $db->query("SELECT id, username, nimi, role FROM users ORDER BY role, username");
while ($row = $result->fetch_assoc()) {
echo sprintf("%-20s %-25s rooli: %s\n", $row['username'], $row['nimi'] ?? '', $row['role']);
}
echo "\n=== KORJAUS: admin → superadmin ===\n";
$updated = $db->query("UPDATE users SET role = 'superadmin' WHERE role = 'admin'");
echo "Päivitetty " . $db->affected_rows . " käyttäjää admin → superadmin\n";
echo "\n=== ROOLIT KORJAUKSEN JÄLKEEN ===\n\n";
$result = $db->query("SELECT id, username, nimi, role FROM users ORDER BY role, username");
while ($row = $result->fetch_assoc()) {
echo sprintf("%-20s %-25s rooli: %s\n", $row['username'], $row['nimi'] ?? '', $row['role']);
}
echo "\n⚠️ POISTA fix_role.php palvelimelta!\n";

View File

@@ -1,80 +0,0 @@
<?php
/**
* Korjaa cuitunet.fi saatavuushaun API-avain ja CORS-originit.
* POISTA TÄMÄ TIEDOSTO KÄYTÖN JÄLKEEN!
* Käyttö: https://intra.noxus.fi/fix_saatavuus.php
*/
require_once __DIR__ . '/db.php';
header('Content-Type: text/plain; charset=utf-8');
$db = getDb();
$targetApiKey = '560160bf6558260e1734e6ad5933cabe';
$requiredOrigins = ['https://cuitunet.fi', 'https://www.cuitunet.fi'];
// Näytä nykyiset yritykset ja niiden API-avaimet
echo "=== YRITYKSET JA API-AVAIMET ===\n\n";
$result = $db->query("SELECT id, nimi, api_key, cors_origins FROM companies ORDER BY nimi");
$companies = [];
while ($row = $result->fetch_assoc()) {
$companies[] = $row;
$key = $row['api_key'] ?: '(tyhjä)';
echo sprintf("%-20s %-40s avain: %s\n", $row['id'], $row['nimi'], $key);
echo sprintf("%-20s %-40s CORS: %s\n", '', '', $row['cors_origins'] ?: '(tyhjä)');
}
// Etsi yritys jossa on "cuitu" nimessä
$cuituCompany = null;
foreach ($companies as $c) {
if (stripos($c['nimi'], 'cuitu') !== false) {
$cuituCompany = $c;
break;
}
}
if (!$cuituCompany) {
// Jos ei löydy nimellä, yritä ensimmäinen yritys
echo "\n⚠️ Ei löytynyt yritystä jossa 'cuitu' nimessä.\n";
echo "Yritykset:\n";
foreach ($companies as $i => $c) {
echo " [$i] {$c['id']} = {$c['nimi']}\n";
}
echo "\nAsetetaan API-avain ENSIMMÄISELLE yritykselle...\n";
$cuituCompany = $companies[0] ?? null;
}
if (!$cuituCompany) {
echo "\n❌ Ei yrityksiä tietokannassa!\n";
exit;
}
echo "\n=== KORJATAAN: {$cuituCompany['nimi']} (ID: {$cuituCompany['id']}) ===\n\n";
// 1. Aseta API-avain
echo "1. API-avain: {$targetApiKey}\n";
$db->query("UPDATE companies SET api_key = '{$targetApiKey}' WHERE id = '{$cuituCompany['id']}'");
echo " → Päivitetty (" . $db->affected_rows . " rivi)\n";
// 2. Päivitä CORS-originit
$existingOrigins = json_decode($cuituCompany['cors_origins'] ?: '[]', true) ?: [];
$merged = array_unique(array_merge($existingOrigins, $requiredOrigins));
$corsJson = json_encode(array_values($merged));
echo "2. CORS-originit: {$corsJson}\n";
$stmt = $db->prepare("UPDATE companies SET cors_origins = ? WHERE id = ?");
$stmt->bind_param('ss', $corsJson, $cuituCompany['id']);
$stmt->execute();
echo " → Päivitetty (" . $stmt->affected_rows . " rivi)\n";
// 3. Testaa
echo "\n=== TARKISTUS ===\n\n";
$result = $db->query("SELECT id, nimi, api_key, cors_origins FROM companies WHERE id = '{$cuituCompany['id']}'");
$row = $result->fetch_assoc();
echo "Yritys: {$row['nimi']}\n";
echo "API-key: {$row['api_key']}\n";
echo "CORS: {$row['cors_origins']}\n";
$match = ($row['api_key'] === $targetApiKey) ? '✅' : '❌';
echo "\nAPI-avain täsmää: {$match}\n";
echo "\n⚠️ POISTA fix_saatavuus.php palvelimelta!\n";
echo "Testaa: curl 'https://intra.noxus.fi/api.php?action=saatavuus&key={$targetApiKey}&osoite=Testikatu+1&postinumero=20100&kaupunki=Turku'\n";

View File

@@ -65,7 +65,8 @@
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
<span id="user-info" class="user-info"></span> <span id="user-info" class="user-info" style="cursor:pointer;" title="Oma profiili"></span>
<button id="btn-profile" class="btn-secondary btn-profile-icon" title="Oma profiili">&#9881;</button>
<select id="company-selector" class="company-selector" style="display:none;"></select> <select id="company-selector" class="company-selector" style="display:none;"></select>
<button id="btn-users" class="btn-secondary" style="display:none">Käyttäjät</button> <button id="btn-users" class="btn-secondary" style="display:none">Käyttäjät</button>
<button id="btn-companies" class="btn-secondary" style="display:none">Yritykset</button> <button id="btn-companies" class="btn-secondary" style="display:none">Yritykset</button>
@@ -565,7 +566,7 @@
<div class="main-container"> <div class="main-container">
<div class="table-card" style="padding:1.5rem;"> <div class="table-card" style="padding:1.5rem;">
<h3 style="color:#0f3460;margin-bottom:1rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;"><span id="api-company-name"></span>Saatavuus-API</h3> <h3 style="color:#0f3460;margin-bottom:1rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;"><span id="api-company-name"></span>Saatavuus-API</h3>
<p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">Julkinen API jolla cuitunet.fi voi tarkistaa kuituverkon saatavuuden osoitteessa. Palauttaa vain osoite + nopeus - ei asiakastietoja.</p> <p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">Julkinen API jolla verkkosivusto voi tarkistaa palvelun saatavuuden osoitteessa. Palauttaa vain osoite + nopeus - ei asiakastietoja.</p>
<div class="form-grid" style="max-width:600px;"> <div class="form-grid" style="max-width:600px;">
<div class="form-group full-width"> <div class="form-group full-width">
<label>API-avain</label> <label>API-avain</label>
@@ -576,7 +577,7 @@
</div> </div>
<div class="form-group full-width"> <div class="form-group full-width">
<label>Sallitut originit (CORS) - yksi per rivi</label> <label>Sallitut originit (CORS) - yksi per rivi</label>
<textarea id="settings-cors" rows="3" style="font-family:monospace;font-size:0.85rem;" placeholder="https://cuitunet.fi&#10;https://www.cuitunet.fi"></textarea> <textarea id="settings-cors" rows="3" style="font-family:monospace;font-size:0.85rem;" placeholder="https://www.yritys.fi&#10;https://yritys.fi"></textarea>
</div> </div>
<div class="form-group full-width"> <div class="form-group full-width">
<button class="btn-primary" id="btn-save-settings">Tallenna asetukset</button> <button class="btn-primary" id="btn-save-settings">Tallenna asetukset</button>
@@ -585,21 +586,21 @@
<p style="color:#888;font-size:0.85rem;margin-top:1rem;">Sähköpostiasetukset (IMAP/postilaatikot) hallitaan Yritykset-välilehdellä.</p> <p style="color:#888;font-size:0.85rem;margin-top:1rem;">Sähköpostiasetukset (IMAP/postilaatikot) hallitaan Yritykset-välilehdellä.</p>
<h3 style="color:#0f3460;margin:1.5rem 0 1rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">API-ohjeet</h3> <h3 style="color:#0f3460;margin:1.5rem 0 1rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">API-ohjeet</h3>
<div style="background:#f8f9fb;padding:1rem;border-radius:8px;font-size:0.85rem;font-family:monospace;overflow-x:auto;"> <div style="background:#f8f9fb;padding:1rem;border-radius:8px;font-size:0.85rem;font-family:monospace;overflow-x:auto;">
<div style="margin-bottom:0.75rem;"><strong>Endpoint:</strong><br>GET https://intra.cuitunet.fi/api.php?action=saatavuus</div> <div style="margin-bottom:0.75rem;"><strong>Endpoint:</strong><br>GET https://&lt;domain&gt;/api.php?action=saatavuus</div>
<div style="margin-bottom:0.75rem;"><strong>Parametrit:</strong><br> <div style="margin-bottom:0.75rem;"><strong>Parametrit:</strong><br>
&bull; <code>key</code> = API-avain (pakollinen)<br> &bull; <code>key</code> = API-avain (pakollinen)<br>
&bull; <code>osoite</code> = Katuosoite ja numero (esim. "Kauppakatu 5")<br> &bull; <code>osoite</code> = Katuosoite ja numero (esim. "Esimerkkikatu 1")<br>
&bull; <code>postinumero</code> = Postinumero (esim. "20100")<br> &bull; <code>postinumero</code> = Postinumero (esim. "20100")<br>
&bull; <code>kaupunki</code> = Kaupunki (esim. "Turku")<br> &bull; <code>kaupunki</code> = Kaupunki (esim. "Turku")<br>
Kaikki kolme pakollisia.</div> Kaikki kolme pakollisia.</div>
<div style="margin-bottom:0.75rem;"><strong>Esimerkki:</strong><br> <div style="margin-bottom:0.75rem;"><strong>Esimerkki:</strong><br>
<code id="api-example-url">api.php?action=saatavuus&key=AVAIN&osoite=Kauppakatu+5&postinumero=20100&kaupunki=Turku</code></div> <code id="api-example-url">api.php?action=saatavuus&key=AVAIN&osoite=Esimerkkikatu+1&postinumero=00100&kaupunki=Helsinki</code></div>
<div><strong>Vastaus:</strong><br> <div><strong>Vastaus:</strong><br>
<code>{"saatavilla":true}</code> tai <code>{"saatavilla":false}</code></div> <code>{"saatavilla":true}</code> tai <code>{"saatavilla":false}</code></div>
</div> </div>
<h3 style="color:#0f3460;margin:1.5rem 0 1rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Testaa API</h3> <h3 style="color:#0f3460;margin:1.5rem 0 1rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Testaa API</h3>
<div style="display:grid;grid-template-columns:1fr;gap:0.5rem;max-width:500px;"> <div style="display:grid;grid-template-columns:1fr;gap:0.5rem;max-width:500px;">
<input type="text" id="test-api-address" placeholder="Osoite (esim. Kauppakatu 5)"> <input type="text" id="test-api-address" placeholder="Osoite (esim. Esimerkkikatu 1)">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem;"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem;">
<input type="text" id="test-api-zip" placeholder="Postinumero" maxlength="5"> <input type="text" id="test-api-zip" placeholder="Postinumero" maxlength="5">
<input type="text" id="test-api-city" placeholder="Kaupunki"> <input type="text" id="test-api-city" placeholder="Kaupunki">
@@ -759,7 +760,7 @@
<div class="form-grid" style="max-width:600px;"> <div class="form-grid" style="max-width:600px;">
<div class="form-group full-width"> <div class="form-group full-width">
<label>Nimi (näkyy tikettilistassa) *</label> <label>Nimi (näkyy tikettilistassa) *</label>
<input type="text" id="mailbox-form-nimi" placeholder="esim. Cuitunet-asiakaspalvelu"> <input type="text" id="mailbox-form-nimi" placeholder="esim. Asiakaspalvelu">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>IMAP-palvelin</label> <label>IMAP-palvelin</label>
@@ -771,7 +772,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Käyttäjätunnus</label> <label>Käyttäjätunnus</label>
<input type="text" id="mailbox-form-user" placeholder="asiakaspalvelu@cuitunet.fi"> <input type="text" id="mailbox-form-user" placeholder="asiakaspalvelu@yritys.fi">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Salasana</label> <label>Salasana</label>
@@ -787,11 +788,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Lähettäjän sähköposti</label> <label>Lähettäjän sähköposti</label>
<input type="text" id="mailbox-form-smtp-email" placeholder="asiakaspalvelu@cuitunet.fi"> <input type="text" id="mailbox-form-smtp-email" placeholder="asiakaspalvelu@yritys.fi">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Lähettäjän nimi</label> <label>Lähettäjän nimi</label>
<input type="text" id="mailbox-form-smtp-name" placeholder="CuituNet Asiakaspalvelu"> <input type="text" id="mailbox-form-smtp-name" placeholder="Yritys Asiakaspalvelu">
</div> </div>
</div> </div>
<div style="display:flex;gap:0.5rem;margin-top:0.75rem;"> <div style="display:flex;gap:0.5rem;margin-top:0.75rem;">
@@ -1019,7 +1020,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="form-laskutuspostinumero">Postinumero</label> <label for="form-laskutuspostinumero">Postinumero</label>
<input type="text" id="form-laskutuspostinumero" placeholder="20100"> <input type="text" id="form-laskutuspostinumero" placeholder="00100">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="form-laskutuskaupunki">Kaupunki</label> <label for="form-laskutuskaupunki">Kaupunki</label>
@@ -1126,6 +1127,45 @@
</div> </div>
</div> </div>
<!-- Oma profiili -modal -->
<div id="profile-modal" class="modal" style="display:none">
<div class="modal-content">
<div class="modal-header">
<h2>Oma profiili</h2>
<button class="modal-close" id="profile-modal-close">&times;</button>
</div>
<form id="profile-form">
<div class="form-grid">
<div class="form-group">
<label>Käyttäjätunnus</label>
<input type="text" id="profile-username" disabled style="background:#f0f2f5;">
</div>
<div class="form-group">
<label for="profile-nimi">Nimi</label>
<input type="text" id="profile-nimi">
</div>
<div class="form-group">
<label for="profile-email">Sähköposti</label>
<input type="email" id="profile-email">
</div>
<div class="form-group">
<label for="profile-password">Uusi salasana <span style="color:#999;font-size:0.82rem;">(jätä tyhjäksi jos ei muuteta)</span></label>
<input type="password" id="profile-password">
</div>
</div>
<div id="profile-signatures-section" style="display:none;margin-top:1rem;border-top:1px solid #e5e7eb;padding-top:1rem;">
<h3 style="color:#0f3460;font-size:1rem;margin-bottom:0.75rem;">Sähköpostiallekirjoitukset</h3>
<p style="color:#888;font-size:0.82rem;margin-bottom:0.75rem;">Allekirjoitus liitetään automaattisesti sähköpostivastausten loppuun.</p>
<div id="profile-signatures-list"></div>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary">Tallenna</button>
<button type="button" class="btn-secondary" id="profile-form-cancel">Peruuta</button>
</div>
</form>
</div>
</div>
<!-- Liidi-modal --> <!-- Liidi-modal -->
<div id="lead-modal" class="modal" style="display:none"> <div id="lead-modal" class="modal" style="display:none">
<div class="modal-content"> <div class="modal-content">

View File

@@ -1,11 +1,11 @@
<!-- <!--
CuituNet Saatavuuswidget Saatavuuswidget
Upota cuitunet.fi-sivulle kopioimalla tämän tiedoston sisältö haluamaasi paikkaan, Upota verkkosivulle kopioimalla tämän tiedoston sisältö haluamaasi paikkaan,
tai lataa script-tagi: tai lataa script-tagi:
<div id="cuitunet-saatavuus"></div> <div id="saatavuus-widget"></div>
<script src="https://intra.cuitunet.fi/saatavuus-widget.js" data-api-key="SINUN_API_AVAIN"></script> <script src="https://intra.yritys.fi/saatavuus-widget.js" data-api-key="SINUN_API_AVAIN"></script>
Tämä on itsenäinen esimerkkisivu testausta varten. Tämä on itsenäinen esimerkkisivu testausta varten.
--> -->
@@ -14,7 +14,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kuituverkon saatavuus - CuituNet</title> <title>Saatavuushaku</title>
<style> <style>
* { margin: 0; padding: 0; box-sizing: border-box; } * { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f2f5; min-height: 100vh; display: flex; align-items: center; justify-content: center; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f2f5; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
@@ -50,7 +50,7 @@
<script> <script>
(function() { (function() {
// MUUTA NÄMÄ // MUUTA NÄMÄ
const API_URL = 'https://intra.cuitunet.fi/api.php'; const API_URL = 'https://intra.yritys.fi/api.php'; // VAIHDA oma domain
const API_KEY = 'VAIHDA_TÄHÄN_API_AVAIMESI'; const API_KEY = 'VAIHDA_TÄHÄN_API_AVAIMESI';
const input = document.getElementById('saatavuus-input'); const input = document.getElementById('saatavuus-input');

View File

@@ -594,9 +594,9 @@ function createLiittymaRow(data = {}, index = 0) {
<button type="button" class="btn-remove-row" title="Poista liittymä">&#10005;</button> <button type="button" class="btn-remove-row" title="Poista liittymä">&#10005;</button>
</div> </div>
<div class="form-grid form-grid-liittyma"> <div class="form-grid form-grid-liittyma">
<div class="form-group"><label>Osoite</label><input type="text" class="l-asennusosoite" value="${esc(data.asennusosoite || '')}" placeholder="esim. Kauppakatu 5"></div> <div class="form-group"><label>Osoite</label><input type="text" class="l-asennusosoite" value="${esc(data.asennusosoite || '')}" placeholder="esim. Esimerkkikatu 1"></div>
<div class="form-group"><label>Postinumero</label><input type="text" class="l-postinumero" value="${esc(data.postinumero || '')}" placeholder="20100"></div> <div class="form-group"><label>Postinumero</label><input type="text" class="l-postinumero" value="${esc(data.postinumero || '')}" placeholder="00100"></div>
<div class="form-group"><label>Kaupunki</label><input type="text" class="l-kaupunki" value="${esc(data.kaupunki || '')}" placeholder="Turku"></div> <div class="form-group"><label>Kaupunki</label><input type="text" class="l-kaupunki" value="${esc(data.kaupunki || '')}" placeholder="Helsinki"></div>
<div class="form-group"><label>Nopeus</label><input type="text" class="l-liittymanopeus" value="${esc(data.liittymanopeus || '')}" placeholder="esim. 100/100"></div> <div class="form-group"><label>Nopeus</label><input type="text" class="l-liittymanopeus" value="${esc(data.liittymanopeus || '')}" placeholder="esim. 100/100"></div>
<div class="form-group"><label>Hinta €/kk</label><input type="number" class="l-hinta" step="0.01" min="0" value="${data.hinta || ''}"></div> <div class="form-group"><label>Hinta €/kk</label><input type="number" class="l-hinta" step="0.01" min="0" value="${data.hinta || ''}"></div>
<div class="form-group"><label>Sopimuskausi</label><select class="l-sopimuskausi"> <div class="form-group"><label>Sopimuskausi</label><select class="l-sopimuskausi">
@@ -1114,6 +1114,76 @@ document.getElementById('user-form').addEventListener('submit', async (e) => {
} catch (e) { alert(e.message); } } catch (e) { alert(e.message); }
}); });
// ==================== OMA PROFIILI ====================
const profileModal = document.getElementById('profile-modal');
document.getElementById('btn-profile').addEventListener('click', openProfileModal);
document.getElementById('user-info').addEventListener('click', openProfileModal);
document.getElementById('profile-modal-close').addEventListener('click', () => profileModal.style.display = 'none');
document.getElementById('profile-form-cancel').addEventListener('click', () => profileModal.style.display = 'none');
async function openProfileModal() {
// Hae tuoreet tiedot
const auth = await apiCall('check_auth');
if (!auth.authenticated) return;
document.getElementById('profile-username').value = auth.username;
document.getElementById('profile-nimi').value = auth.nimi || '';
document.getElementById('profile-email').value = auth.email || '';
document.getElementById('profile-password').value = '';
// Allekirjoitukset
const sigSection = document.getElementById('profile-signatures-section');
const sigList = document.getElementById('profile-signatures-list');
const userSigs = auth.signatures || {};
try {
const mailboxes = await apiCall('all_mailboxes');
if (mailboxes.length === 0) {
sigSection.style.display = 'none';
} else {
sigSection.style.display = '';
sigList.innerHTML = mailboxes.map(mb =>
`<div style="margin-bottom:0.75rem;">
<label style="font-weight:600;font-size:0.85rem;color:#333;">${esc(mb.company_nimi)}${esc(mb.nimi)}</label>
<textarea class="profile-sig-textarea" data-mailbox-id="${mb.id}" rows="3"
style="width:100%;margin-top:0.25rem;padding:8px;border:1px solid #ddd;border-radius:6px;font-size:0.85rem;font-family:inherit;resize:vertical;"
placeholder="esim.\nNimi\nYritys Oy\ninfo@yritys.fi">${esc(userSigs[mb.id] || '')}</textarea>
</div>`
).join('');
}
} catch {
sigSection.style.display = 'none';
}
profileModal.style.display = 'flex';
}
document.getElementById('profile-form').addEventListener('submit', async (e) => {
e.preventDefault();
const signatures = {};
document.querySelectorAll('.profile-sig-textarea').forEach(ta => {
const mbId = ta.dataset.mailboxId;
const val = ta.value.trim();
if (val) signatures[mbId] = val;
});
const data = {
nimi: document.getElementById('profile-nimi').value,
email: document.getElementById('profile-email').value,
signatures,
};
const pw = document.getElementById('profile-password').value;
if (pw) data.password = pw;
try {
await apiCall('profile_update', 'POST', data);
// Päivitä UI
const auth = await apiCall('check_auth');
if (auth.authenticated) {
currentUser = { username: auth.username, nimi: auth.nimi, role: auth.role, id: auth.user_id };
currentUserSignatures = auth.signatures || {};
document.getElementById('user-info').textContent = auth.nimi || auth.username;
}
profileModal.style.display = 'none';
alert('Profiili päivitetty!');
} catch (e) { alert(e.message); }
});
// ==================== TICKETS (ASIAKASPALVELU) ==================== // ==================== TICKETS (ASIAKASPALVELU) ====================
let tickets = []; let tickets = [];
@@ -1875,7 +1945,7 @@ async function loadSettings() {
const apiTitle = document.getElementById('api-company-name'); const apiTitle = document.getElementById('api-company-name');
if (apiTitle && currentCompany) apiTitle.textContent = currentCompany.nimi + ' — '; if (apiTitle && currentCompany) apiTitle.textContent = currentCompany.nimi + ' — ';
const key = config.api_key || 'AVAIN'; const key = config.api_key || 'AVAIN';
document.getElementById('api-example-url').textContent = `api.php?action=saatavuus&key=${key}&osoite=Kauppakatu+5&postinumero=20100&kaupunki=Turku`; document.getElementById('api-example-url').textContent = `api.php?action=saatavuus&key=${key}&osoite=Esimerkkikatu+1&postinumero=00100&kaupunki=Helsinki`;
// Telegram-asetukset // Telegram-asetukset
document.getElementById('settings-telegram-token').value = config.telegram_bot_token || ''; document.getElementById('settings-telegram-token').value = config.telegram_bot_token || '';
@@ -1981,7 +2051,7 @@ document.getElementById('btn-generate-key').addEventListener('click', async () =
try { try {
const config = await apiCall('generate_api_key', 'POST'); const config = await apiCall('generate_api_key', 'POST');
document.getElementById('settings-api-key').value = config.api_key || ''; document.getElementById('settings-api-key').value = config.api_key || '';
document.getElementById('api-example-url').textContent = `api.php?action=saatavuus&key=${config.api_key}&osoite=Kauppakatu+5&postinumero=20100&kaupunki=Turku`; document.getElementById('api-example-url').textContent = `api.php?action=saatavuus&key=${config.api_key}&osoite=Esimerkkikatu+1&postinumero=00100&kaupunki=Helsinki`;
} catch (e) { alert(e.message); } } catch (e) { alert(e.message); }
}); });

View File

@@ -193,6 +193,12 @@ header {
padding-right: 0.5rem; padding-right: 0.5rem;
border-right: 1px solid rgba(255,255,255,0.2); border-right: 1px solid rgba(255,255,255,0.2);
} }
.user-info:hover { opacity: 1; text-decoration: underline; }
.btn-profile-icon {
padding: 4px 8px !important;
font-size: 0.9rem !important;
min-width: unset;
}
/* Main container */ /* Main container */
.main-container { .main-container {