update pages

This commit is contained in:
themohooks 2025-05-25 15:04:03 +03:00
parent 08ae408bdf
commit 1a266eb6aa
15 changed files with 1825 additions and 961 deletions

View file

@ -23,20 +23,24 @@ if (Auth::userid() > 0) {
<tr>
<td class="main">
<center>
<h1>Вход на сайт</h1>
<h1><b>Авторизация</b></h1>
<div class="mf-center-block mf-label">
<form id="form" method="post" class="p20i mf-center-block-wide mf-label">
<input type="hidden" name="ref" value="/">
<input type="text" name="username" id="username" class="mf-input-wide" placeholder="Имя или e-mail" value="">
<div class="styled-input">
<input type="text" name="username" id="username" required>
<label for="username">Имя или Email</label>
</div>
<div style="color:#e00" id="err_username"></div>
<input type="password" name="password" id="password" class="mf-input-wide" placeholder="Пароль">
<div class="styled-input">
<input type="password" name="password" id="password" required>
<label for="username">Пароль</label>
</div>
<div style="color:#e00" id="err_password"></div>
<input type="button" id="loginbtn" class="mf-button-wide" value="Войти">
<input type="button" id="loginbtn" class="mf-button-wide" value="Войти"style="margin-top:15px" >
</form>

View file

@ -74,7 +74,7 @@ LIMIT 10;');
$photo = DB::query('SELECT * FROM photos WHERE id=:id', array(':id' => $pd['photo_id']));
foreach ($photo as $p) {
$author = new User($p['user_id']);
echo '<a href="/photo/' . $p['id'] . '" target="_blank" class="prw pop-prw">
echo '<a href="/photo/' . $p['id'] . '" class="prw pop-prw">
<img width="250" src="/api/photo/compress?url=' . $p['photourl'] . '">
<div class="hpshade">
<div class="eye-icon">+' . $pd['view_count'] . '</div>
@ -100,7 +100,7 @@ LIMIT 10;');
<td style="vertical-align:top; width:70%; padding-top:4px">
<h4><a href="/photo/" target="_blank">Случайные фотографии</a></h4>
<h4><a href="/photo/">Случайные фотографии</a></h4>
<div id="random-photos" class="ix-photos ix-photos-oneline">
<?php
$photos = DB::query('SELECT * FROM photos WHERE moderated=1 ORDER BY RAND() DESC LIMIT 7');
@ -116,7 +116,7 @@ LIMIT 10;');
<div>' . $date . '</div>
</div>
'; ?>
<a href="/photo/<?= $p['id'] ?>" target="_blank" class="prw-animate" style='background-image:url("/api/photo/compress?url=<?= $p['photourl'] ?>")'></a>
<a href="/photo/<?= $p['id'] ?>" class="prw-animate" style='background-image:url("/api/photo/compress?url=<?= $p['photourl'] ?>")'></a>
<?php echo '
</div>';
}

287
views/pages/MapMedia.php Normal file
View file

@ -0,0 +1,287 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\{Vehicle, User};
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<style>
#mapd {
height: 50vh;
}
.custom-tooltip {
background: white;
border: 2px solid #ccc;
padding: 10px;
border-radius: 5px;
max-width: 200px;
}
</style>
<style>
.blur-image {
filter: blur(5px);
transition: filter 0.5s ease, opacity 0.3s ease;
opacity: 0.9;
}
.loaded-image {
filter: none;
opacity: 1;
}
.marker-container {
position: relative;
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.marker-badge {
position: absolute;
bottom: 2px;
right: 2px;
background: white;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.photo-popup {
max-width: 300px;
}
.photo-popup img {
max-width: 100%;
height: auto;
display: block;
}
.map-notification {
position: fixed;
bottom: 20px;
right: 20px;
padding: 15px;
background: #ff4444;
color: white;
border-radius: 5px;
z-index: 1000;
}
</style>
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">
<h1>Map Media</h1>
<div id="mapd"></div>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
</td>
</tr>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
<script>
const map = L.map('mapd').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
let loadedPhotoIds = new Set();
let abortController = null;
const markers = L.markerClusterGroup();
const cachedOriginals = new Map();
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
const loadPhotos = debounce(async () => {
try {
if (abortController) abortController.abort();
const newController = new AbortController();
abortController = newController;
const bounds = map.getBounds();
const params = new URLSearchParams({
north: bounds.getNorth().toFixed(6),
south: bounds.getSouth().toFixed(6),
west: bounds.getWest().toFixed(6),
east: bounds.getEast().toFixed(6),
zoom: map.getZoom()
});
const response = await fetch(`/api/photo/loadmap?${params}`, {
signal: newController.signal
});
if (!response.ok) throw new Error('Ошибка сети');
const photos = await response.json();
photos.forEach(photo => {
if (loadedPhotoIds.has(photo.id)) return;
const img = document.createElement('img');
img.src = photo.thumb;
img.className = 'blur-image';
img.onload = () => img.classList.add('loaded-image');
const marker = L.marker([photo.lat, photo.lng], {
icon: L.divIcon({
className: 'custom-marker',
html: `
<div class="marker-container">
${img.outerHTML}
<div class="marker-badge">📷</div>
</div>
`
})
});
marker.on('click', function() {
const popupContent = document.createElement('div');
popupContent.className = 'photo-modal-content';
const imageContainer = document.createElement('div');
imageContainer.className = 'image-container';
if (cachedOriginals.has(photo.id)) {
const imgFull = new Image();
imgFull.src = cachedOriginals.get(photo.id);
imgFull.className = 'full-image loaded-image';
imageContainer.appendChild(imgFull);
} else {
const imgSmall = document.createElement('img');
imgSmall.src = photo.photourl_small;
imgSmall.className = 'blur-image preview-image';
imageContainer.appendChild(imgSmall);
const imgFull = new Image();
imgFull.className = 'full-image blur-image';
imgFull.onload = () => {
cachedOriginals.set(photo.id, photo.photourl);
imgFull.classList.add('loaded-image');
imgSmall.style.opacity = '0';
};
imgFull.src = photo.photourl;
imageContainer.appendChild(imgFull);
}
popupContent.appendChild(imageContainer);
const modal = L.popup()
.setLatLng([photo.lat, photo.lng])
.setContent(popupContent)
.openOn(map);
});
markers.addLayer(marker);
loadedPhotoIds.add(photo.id);
});
map.addLayer(markers);
} catch (err) {
if (err.name !== 'AbortError') {
console.error('Ошибка загрузки:', err);
showErrorNotification('Ошибка загрузки данных');
}
}
}, 300);
map.on('moveend', loadPhotos);
map.on('zoomend', loadPhotos);
map.on('dragend', loadPhotos);
loadPhotos();
function showErrorNotification(message) {
const notification = document.createElement('div');
notification.className = 'map-notification error';
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
}
</script>
<style>
.photo-modal-content {
width: 250px;
height: 250px;
}
.image-container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.preview-image,
.full-image {
position: absolute;
top: 0;
left: 0;
width: 250px;
height: 250px;
object-fit: cover;
transition: all 0.5s ease-in-out;
}
.blur-image {
filter: blur(20px);
opacity: 1;
}
.loaded-image {
filter: blur(0);
opacity: 1;
}
.full-image {
opacity: 0;
}
.full-image.loaded-image {
opacity: 1;
}
.preview-image {
transition: opacity 0.5s ease-in-out;
}
</style>
</table>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,7 @@ $birthdate = json_decode($userprofile->i('content'), true)['aboutbirthday']['val
if ($userprofile->i('id') === Auth::userid()) { ?>
<p><b><a href="/lk/profile">Редактировать мой профиль</a></b></p>
<?php } ?>
<div class="p20" style="padding-right:12px; background-color: white !important;">
<div class="p20" style="padding-right:12px;">
<table width="100%">
<tr>
<?php if ($userprofile->content('badge') !== null) { ?>
@ -225,7 +225,7 @@ $birthdate = json_decode($userprofile->i('content'), true)['aboutbirthday']['val
<div class="p20" style="margin-top: 8px; background-color: white !important;">
<h4>О себе</h4>
<?=
htmlspecialchars($about)
nl2br(htmlspecialchars($about))
?>
</div>
<?php } else if ($usercttc === True) {

View file

View file

@ -42,6 +42,7 @@ use \App\Models\{User, Photo};
<th width="90%">Информация</th>
<th></th>
<th class="c nw">Покинуло очередь</th>
<th class="c nw">Действия</th>
</tr>
<?php
@ -80,11 +81,25 @@ use \App\Models\{User, Photo};
if ($p['endmoderation'] === -1) {
$endm = 'На модерации';
} else {
$endm = Date::zmdate($p['endmoderation']).'<div style="margin-top:15px">Оценка<br><b>И+ К+</b></div>';
if ($photo->content('iRate') === 0) {
$irate = '-';
} else {
$irate = '+';
}
if ($photo->content('kRate') === 0) {
$krate = '-';
} else {
$krate = '+';
}
$endm = Date::zmdate($p['endmoderation']).'<div style="margin-top:15px">Оценка<br><b>И'.$irate.' К'.$irate.'</b></div>';
}
echo '
<td class="cs">'.$endm.'
</td>';
echo '
<td class="cs"><a type="button" href="/lk/editimage?id='.$p['id'].'">Редактировать</a>
</td>
</tr>';
}

View file

@ -1,5 +1,4 @@
<?php
use \App\Services\{Auth, DB, Date};
use \App\Models\User;
@ -22,297 +21,19 @@ $user = new User(Auth::userid());
<tr>
<td class="main">
<center>
<h1>Настройки профиля</h1>
<script src="/js/jquery.form.min.js"></script>
<script>
var bigPhoto = '';
var uploadPhoto, removePhoto;
$(document).ready(function() {
$('#form').ajaxForm({
url: '/api/profile/update',
dataType: 'text',
beforeSubmit: function() {
$('#applied').hide();
$('#errors').hide();
$('#submitBtn').val('Отправка данных...').prop('disabled', true);
uploadPhoto = ($('#userphoto_file').val() != '');
removePhoto = $('#remove_userphoto').is(':checked');
},
success: function(data) {
$('#submitBtn').val('Отредактировать профиль').prop('disabled', false);
if (data == '' || data == 'refresh') {
$('#applied').show();
if (removePhoto) {
bigPhoto = '';
$('#userphoto_div').hide();
} else
if (uploadPhoto || bigPhoto != '') {
bigPhoto = '/_update_temp/userphotos/' + 140 + '.jpg';
$('#userphoto_img').attr('src', '/_update_temp/userphotos/' + 140 + '_s.jpg');
$('#userphoto_div').show();
$('#remove_userphoto').prop('checked', false);
$('#userphoto_file').val('');
}
if (data == 'refresh') window.location.reload();
} else $('#errors').html(data).show();
}
});
$('#userphotoLink').click(function(e) {
$('#userphoto_big_img').attr('src', bigPhoto);
$('#userphoto_big_div').css('top', (getBodyScrollTop() + 10) + 'px').show();
e.stopPropagation();
return false;
});
$(document).click(function(e) {
if ($(e.target).closest('#userphoto_big_div').length == 0)
$('#userphoto_big_div').hide();
});
});
var errorElements = [];
function getBodyScrollTop() {
return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || (document.body && document.body.scrollTop);
}
function hideUserPhoto() {
$('#userphoto_big_div').hide();
}
</script>
<div id="userphoto_big_div" style="position:absolute; display:none; padding:10px; background-color:white; margin:auto; text-align:center; left:10px" class="p5 shadow"><a href="#" onclick="hideUserPhoto(); return false"><img alt="" src="" id="userphoto_big_img" border="0"></a><br><br><a href="#" onclick="hideUserPhoto(); return false">закрыть</a></div>
<p>Ссылка на публичный профиль: <b><a href="/author/<?= Auth::userid() ?>/" class="nw"><?= $user->i('username') ?></a></b></p>
<form method="post" name="form" id="form" enctype="multipart/form-data" style="display:inline-block">
<?php
function getSelectedCountryId()
{
$user = new User(Auth::userid());
$result = json_decode($user->i('content'), true)['aboutrid']['value'];
return $result;
}
$selectedCountryId = getSelectedCountryId();
$optionsHtml = '
<option value="0">(Без страны)</option>
<option value="24">Абхазия</option>
<option value="49">Австралия</option>
<option value="27">Австрия</option>
<option value="81">Австро-Венгрия</option>
<option value="31">Азербайджан</option>
<option value="70">Албания</option>
<option value="80">Алжир</option>
<option value="34">Аргентина</option>
<option value="25">Армения</option>
<option value="2">Беларусь</option>
<option value="53">Бельгия</option>
<option value="39">Болгария</option>
<option value="58">Босния и Герцеговина</option>
<option value="64">Бразилия</option>
<option value="47">Великобритания</option>
<option value="75">Венгерская народная республика</option>
<option value="43">Венгрия</option>
<option value="84">Вьетнам</option>
<option value="72">ГДР</option>
<option value="93">Гвинейская Республика</option>
<option value="15">Германия</option>
<option value="76">Германская империя</option>
<option value="71">Греция</option>
<option value="32">Грузия</option>
<option value="65">Дания</option>
<option value="97">Донецкая Народная Республика</option>
<option value="105">Европа (временно)</option>
<option value="91">Египет</option>
<option value="33">Израиль</option>
<option value="69">Индия</option>
<option value="90">Иордания</option>
<option value="82">Ирак</option>
<option value="68">Иран</option>
<option value="95">Ирландия</option>
<option value="54">Испания</option>
<option value="37">Италия</option>
<option value="85">КНДР</option>
<option value="3">Казахстан</option>
<option value="60">Канада</option>
<option value="61">Китай</option>
<option value="87">Косово</option>
<option value="66">Крым</option>
<option value="41">Куба</option>
<option value="12">Кыргызстан</option>
<option value="17">Латвия</option>
<option value="30">Ливия</option>
<option value="21">Литва</option>
<option value="98">Луганская Народная Республика</option>
<option value="51">Люксембург</option>
<option value="20">Молдова</option>
<option value="29">Монголия</option>
<option value="101">Намибия</option>
<option value="22">Нидерланды</option>
<option value="88">Новая Зеландия</option>
<option value="16">Норвегия</option>
<option value="89">Объединённые Арабские Эмираты</option>
<option value="104">Пакистан</option>
<option value="96">Панама</option>
<option value="100">Перу</option>
<option value="19">Польша</option>
<option value="55">Португалия</option>
<option value="67">Приднестровье</option>
<option value="79">Протекторат Богемии и Моравии</option>
<option value="102">РСФСР</option>
<option value="1">Россия</option>
<option value="ex_1">Российская Империя</option>
<option value="40">Румыния</option>
<option value="77">Румынская Народная Республика</option>
<option value="10">СССР</option>
<option value="38">США</option>
<option value="59">Северная Македония</option>
<option value="44">Сербия</option>
<option value="62">Сирия</option>
<option value="42">Словакия</option>
<option value="56">Словения</option>
<option value="78">Советская зона оккупации Герма</option>
<option value="36">Таджикистан</option>
<option value="63">Таиланд</option>
<option value="99">Тайвань</option>
<option value="86">Тунис</option>
<option value="35">Туркменистан</option>
<option value="52">Турция</option>
<option value="103">УССР</option>
<option value="28">Узбекистан</option>
<option value="4">Украина</option>
<option value="74">Уругвай</option>
<option value="14">Финляндия</option>
<option value="23">Франция</option>
<option value="57">Хорватия</option>
<option value="45">Черногория</option>
<option value="18">Чехия</option>
<option value="11">Чехословакия</option>
<option value="46">Швейцария</option>
<option value="50">Швеция</option>
<option value="83">Шри-Ланка</option>
<option value="13">Эстония</option>
<option value="94">Югославия</option>
<option value="92">Южная Корея</option>
<option value="48">Япония</option>
<option value="26">Прочее</option>
';
function addSelectedAttribute($optionsHtml, $selectedValue)
{
return preg_replace_callback(
'/<option value="(\d+)"(.*?)>(.*?)<\/option>/',
function ($matches) use ($selectedValue) {
$selected = ($matches[1] == $selectedValue) ? ' selected' : '';
return '<option value="' . $matches[1] . '"' . $selected . $matches[2] . '>' . $matches[3] . '</option>';
},
$optionsHtml
);
}
?>
<div class="p20" style="text-align:left; margin-bottom:15px">
<h4>Информация</h4>
<div style="margin-bottom:3px; margin-top:5px">Страна:</div>
<select name="aboutrid" style="width:100%">
<?= addSelectedAttribute($optionsHtml, $selectedCountryId) ?>
</select>
<div style="margin-bottom:3px; margin-top:5px">Откуда:</div>
<input type="text" name="aboutlive" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutlive']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Дата рождения</div>
<input type="text" name="aboutbirthday" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutbirthday']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Владение языками</div>
<input type="text" name="aboutlangs" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutlangs']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Пол</div>
<select name="sex" style="width:100%">
<option value="0">(не указан)</option>
<option value="1" selected="">мужской</option>
<option value="2">женский</option>
</select>
<div class="tabs">
<nav class="tab-nav">
<a href="/lk/profile" class="tab-item <?php if ($_GET['type'] === null) { ?> active <?php } ?>">Профиль</a>
<a href="?type=Security" class="tab-item <?php if ($_GET['type'] === 'Security') { ?> active <?php } ?>">Безопасность</a>
<a href="?type=Personalization" class="tab-item <?php if ($_GET['type'] === 'Personalization') { ?> active <?php } ?>">Внешний вид</a>
</nav>
<div class="tab-content">
<?=\App\Controllers\ProfileController::loadContent();?>
<script src="/js/jquery.form.min.js"></script>
</div>
</div>
<div class="p20" style="text-align:left; margin-bottom:15px">
<h4>О себе</h4>
<div style="margin-bottom:15px">
<textarea name="aboutmemo" style="width:100%; height:200px"><?= json_decode($user->i('content'), true)['aboutmemo']['value'] ?></textarea>
</div>
<div class="sm">BBcode: [b] [i] [u] [s] [sub] [sup] [size] [img] [url]</div>
<div style="margin-bottom:3px; margin-top:5px">Telegram</div>
<input type="text" name="abouttelegram" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['abouttelegram']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">ВКонтакте</div>
<input type="text" name="aboutvk" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutvk']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Twitter/X</div>
<input type="text" name="abouttwitter" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['abouttwitter']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">YouTube</div>
<input type="text" name="aboutyoutube" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutyoutube']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Почта</div>
<input type="text" name="aboutemail" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutemail']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Instagram</div>
<input type="text" name="aboutinstagram" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutinstagram']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">TransPhoto</div>
<input type="text" name="abouttransphoto" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['abouttransphoto']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Личный сайт</div>
<input type="text" name="aboutwebsite" id="live" style="width:100%; margin-bottom: 35px;" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutwebsite']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Любимые модели поездов</div>
<input type="text" name="aboutfavs_trains" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutfavs_trains']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Любимые страны</div>
<input type="text" name="aboutfavs_countries" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutfavs_countries']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Любимые города</div>
<input type="text" name="aboutfavs_cities" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutfavs_cities']['value'] ?>">
<div style="margin-bottom:7px"><b>Фотография</b></div>
<div style="margin-bottom:15px">
<div id="userphoto_div" style="display:none">
<a href="#" id="userphotoLink"><img src="" alt="" id="userphoto_img" class="f" style="width:auto; max-width:250px"></a>
<div style="margin-top:5px; margin-bottom:7px" class="sm"><input type="checkbox" name="remove_userphoto" id="remove_userphoto"> <label for="remove_userphoto">удалить</label></div>
</div>
<div id="userphoto_file_span"><input type="file" name="userphoto" id="userphoto_file" accept="image/*"></div>
<div class="sm" style="margin-top:3px; color:#888">Для загрузки принимаются файлы JPEG объемом до 200 КБ и шириной не более 800 пикселей</div>
</div>
<div style="text-align:center; margin-top:25px">
<input type="submit" id="submitBtn" style="width:250px; height:30px; margin-bottom:5px" value="Отредактировать профиль">
<div><span style="color:red; font-weight:bold; display:none" id="errors"></span><span style="display:none; font-weight:bold; color:green" id="applied">&ensp;Изменения внесены</span></div>
</div>
</div>
</form>
</center>
</td>
</tr>

View file

@ -0,0 +1,297 @@
<?php
use \App\Services\{Auth, DB};
use \App\Models\User;
$user = new User(Auth::userid());
?>
<script>
var bigPhoto = '';
var uploadPhoto, removePhoto;
$(document).ready(function() {
$('#form').ajaxForm({
url: '/api/profile/update',
dataType: 'text',
beforeSubmit: function() {
$('#applied').hide();
$('#errors').hide();
$('#submitBtn').val('Отправка данных...').prop('disabled', true);
uploadPhoto = ($('#userphoto_file').val() != '');
removePhoto = $('#remove_userphoto').is(':checked');
},
success: function(data) {
$('#submitBtn').val('Отредактировать профиль').prop('disabled', false);
if (data == '' || data == 'refresh') {
$('#applied').show();
if (removePhoto) {
bigPhoto = '';
$('#userphoto_div').hide();
} else
if (uploadPhoto || bigPhoto != '') {
bigPhoto = '/_update_temp/userphotos/' + 140 + '.jpg';
$('#userphoto_img').attr('src', '/_update_temp/userphotos/' + 140 + '_s.jpg');
$('#userphoto_div').show();
$('#remove_userphoto').prop('checked', false);
$('#userphoto_file').val('');
}
if (data == 'refresh') window.location.reload();
} else $('#errors').html(data).show();
}
});
$('#userphotoLink').click(function(e) {
$('#userphoto_big_img').attr('src', bigPhoto);
$('#userphoto_big_div').css('top', (getBodyScrollTop() + 10) + 'px').show();
e.stopPropagation();
return false;
});
$(document).click(function(e) {
if ($(e.target).closest('#userphoto_big_div').length == 0)
$('#userphoto_big_div').hide();
});
});
var errorElements = [];
function getBodyScrollTop() {
return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || (document.body && document.body.scrollTop);
}
function hideUserPhoto() {
$('#userphoto_big_div').hide();
}
</script>
<div id="userphoto_big_div" style="position:absolute; display:none; padding:10px; background-color:white; margin:auto; text-align:center; left:10px" class="p5 shadow"><a href="#" onclick="hideUserPhoto(); return false"><img alt="" src="" id="userphoto_big_img" border="0"></a><br><br><a href="#" onclick="hideUserPhoto(); return false">закрыть</a></div>
<p>Ссылка на публичный профиль: <b><a href="/author/<?= Auth::userid() ?>/" class="nw"><?= $user->i('username') ?></a></b></p>
<form method="post" name="form" id="form" enctype="multipart/form-data" style="display:inline-block">
<?php
function getSelectedCountryId()
{
$user = new User(Auth::userid());
$result = json_decode($user->i('content'), true)['aboutrid']['value'];
return $result;
}
$selectedCountryId = getSelectedCountryId();
$optionsHtml = '
<option value="0">(Без страны)</option>
<option value="24">Абхазия</option>
<option value="49">Австралия</option>
<option value="27">Австрия</option>
<option value="81">Австро-Венгрия</option>
<option value="31">Азербайджан</option>
<option value="70">Албания</option>
<option value="80">Алжир</option>
<option value="34">Аргентина</option>
<option value="25">Армения</option>
<option value="2">Беларусь</option>
<option value="53">Бельгия</option>
<option value="39">Болгария</option>
<option value="58">Босния и Герцеговина</option>
<option value="64">Бразилия</option>
<option value="47">Великобритания</option>
<option value="75">Венгерская народная республика</option>
<option value="43">Венгрия</option>
<option value="84">Вьетнам</option>
<option value="72">ГДР</option>
<option value="93">Гвинейская Республика</option>
<option value="15">Германия</option>
<option value="76">Германская империя</option>
<option value="71">Греция</option>
<option value="32">Грузия</option>
<option value="65">Дания</option>
<option value="97">Донецкая Народная Республика</option>
<option value="105">Европа (временно)</option>
<option value="91">Египет</option>
<option value="33">Израиль</option>
<option value="69">Индия</option>
<option value="90">Иордания</option>
<option value="82">Ирак</option>
<option value="68">Иран</option>
<option value="95">Ирландия</option>
<option value="54">Испания</option>
<option value="37">Италия</option>
<option value="85">КНДР</option>
<option value="3">Казахстан</option>
<option value="60">Канада</option>
<option value="61">Китай</option>
<option value="87">Косово</option>
<option value="66">Крым</option>
<option value="41">Куба</option>
<option value="12">Кыргызстан</option>
<option value="17">Латвия</option>
<option value="30">Ливия</option>
<option value="21">Литва</option>
<option value="98">Луганская Народная Республика</option>
<option value="51">Люксембург</option>
<option value="20">Молдова</option>
<option value="29">Монголия</option>
<option value="101">Намибия</option>
<option value="22">Нидерланды</option>
<option value="88">Новая Зеландия</option>
<option value="16">Норвегия</option>
<option value="89">Объединённые Арабские Эмираты</option>
<option value="104">Пакистан</option>
<option value="96">Панама</option>
<option value="100">Перу</option>
<option value="19">Польша</option>
<option value="55">Португалия</option>
<option value="67">Приднестровье</option>
<option value="79">Протекторат Богемии и Моравии</option>
<option value="102">РСФСР</option>
<option value="1">Россия</option>
<option value="ex_1">Российская Империя</option>
<option value="40">Румыния</option>
<option value="77">Румынская Народная Республика</option>
<option value="10">СССР</option>
<option value="38">США</option>
<option value="59">Северная Македония</option>
<option value="44">Сербия</option>
<option value="62">Сирия</option>
<option value="42">Словакия</option>
<option value="56">Словения</option>
<option value="78">Советская зона оккупации Герма</option>
<option value="36">Таджикистан</option>
<option value="63">Таиланд</option>
<option value="99">Тайвань</option>
<option value="86">Тунис</option>
<option value="35">Туркменистан</option>
<option value="52">Турция</option>
<option value="103">УССР</option>
<option value="28">Узбекистан</option>
<option value="4">Украина</option>
<option value="74">Уругвай</option>
<option value="14">Финляндия</option>
<option value="23">Франция</option>
<option value="57">Хорватия</option>
<option value="45">Черногория</option>
<option value="18">Чехия</option>
<option value="11">Чехословакия</option>
<option value="46">Швейцария</option>
<option value="50">Швеция</option>
<option value="83">Шри-Ланка</option>
<option value="13">Эстония</option>
<option value="94">Югославия</option>
<option value="92">Южная Корея</option>
<option value="48">Япония</option>
<option value="26">Прочее</option>
';
function addSelectedAttribute($optionsHtml, $selectedValue)
{
return preg_replace_callback(
'/<option value="(\d+)"(.*?)>(.*?)<\/option>/',
function ($matches) use ($selectedValue) {
$selected = ($matches[1] == $selectedValue) ? ' selected' : '';
return '<option value="' . $matches[1] . '"' . $selected . $matches[2] . '>' . $matches[3] . '</option>';
},
$optionsHtml
);
}
?>
<div class="p20" style="text-align:left; margin-bottom:15px">
<h4>Информация</h4>
<div style="margin-bottom:3px; margin-top:5px">Страна:</div>
<select name="aboutrid" style="width:100%">
<?= addSelectedAttribute($optionsHtml, $selectedCountryId) ?>
</select>
<div style="margin-bottom:3px; margin-top:5px">Откуда:</div>
<input type="text" name="aboutlive" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutlive']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Дата рождения</div>
<input type="text" name="aboutbirthday" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutbirthday']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Владение языками</div>
<input type="text" name="aboutlangs" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutlangs']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Пол</div>
<select name="sex" style="width:100%">
<option value="0">(не указан)</option>
<option value="1" selected="">мужской</option>
<option value="2">женский</option>
</select>
</div>
<div class="p20" style="text-align:left; margin-bottom:15px">
<h4>О себе</h4>
<div style="margin-bottom:15px">
<textarea name="aboutmemo" style="width:100%; height:200px"><?= json_decode($user->i('content'), true)['aboutmemo']['value'] ?></textarea>
</div>
<div class="sm">BBcode: [b] [i] [u] [s] [sub] [sup] [size] [img] [url]</div>
<div style="margin-bottom:3px; margin-top:5px">Telegram</div>
<input type="text" name="abouttelegram" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['abouttelegram']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">ВКонтакте</div>
<input type="text" name="aboutvk" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutvk']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Twitter/X</div>
<input type="text" name="abouttwitter" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['abouttwitter']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">YouTube</div>
<input type="text" name="aboutyoutube" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutyoutube']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Почта</div>
<input type="text" name="aboutemail" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutemail']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Instagram</div>
<input type="text" name="aboutinstagram" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutinstagram']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">TransPhoto</div>
<input type="text" name="abouttransphoto" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['abouttransphoto']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Личный сайт</div>
<input type="text" name="aboutwebsite" id="live" style="width:100%; margin-bottom: 35px;" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutwebsite']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Любимые модели поездов</div>
<input type="text" name="aboutfavs_trains" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutfavs_trains']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Любимые страны</div>
<input type="text" name="aboutfavs_countries" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutfavs_countries']['value'] ?>">
<div style="margin-bottom:3px; margin-top:5px">Любимые города</div>
<input type="text" name="aboutfavs_cities" id="live" style="width:100%" maxlength="50" value="<?= json_decode($user->i('content'), true)['aboutfavs_cities']['value'] ?>">
<div style="margin-bottom:7px"><b>Фотография</b></div>
<div style="margin-bottom:15px">
<div id="userphoto_div" style="display:none">
<a href="#" id="userphotoLink"><img src="" alt="" id="userphoto_img" class="f" style="width:auto; max-width:250px"></a>
<div style="margin-top:5px; margin-bottom:7px" class="sm"><input type="checkbox" name="remove_userphoto" id="remove_userphoto"> <label for="remove_userphoto">удалить</label></div>
</div>
<div id="userphoto_file_span"><input type="file" name="userphoto" id="userphoto_file" accept="image/*"></div>
<div class="sm" style="margin-top:3px; color:#888">Для загрузки принимаются файлы JPEG объемом до 200 КБ и шириной не более 800 пикселей</div>
</div>
<div style="text-align:center; margin-top:25px">
<input type="submit" id="submitBtn" style="width:250px; height:30px; margin-bottom:5px" value="Отредактировать профиль">
<div><span style="color:red; font-weight:bold; display:none" id="errors"></span><span style="display:none; font-weight:bold; color:green" id="applied">&ensp;Изменения внесены</span></div>
</div>
</div>
</form>

View file

@ -0,0 +1,65 @@
<?php
session_start();
use \App\Services\{Auth, DB, ThemeManager};
use \App\Models\User;
$themeManager = new ThemeManager();
$themeManager->loadThemes();
$themesList = $themeManager->getAllThemes();
var_dump($_SESSION);
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['theme_id'])) {
try {
$themeManager->saveThemeToProfile($_POST['theme_id']);
header('Location: ' . $_SERVER['REQUEST_URI']);
exit;
} catch (Exception $e) {
error_log($e->getMessage());
}
}
?>
<form method="post" name="form" id="form" enctype="multipart/form-data" style="display:inline-block">
<div class="p20" style="text-align:left; margin-bottom:15px">
<h4>Оформление сайта</h4>
<div style="margin-bottom:3px; margin-top:5px">Тема</div>
<select name="theme_id" style="width:100%" onchange="this.form.submit()">
<option value="standard" <?= $selectedTheme === 'standard' ? 'selected' : '' ?>>Стандартная</option>
<?php foreach ($themesList as $t): ?>
<option value="<?= htmlspecialchars($t['id']) ?>"
<?= $selectedTheme === $t['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($t['name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div style="text-align:center; margin-top:25px">
<input type="submit" id="submitBtn" style="width:250px; height:30px; margin-bottom:5px" value="Сохранить">
<div><span style="color:red; font-weight:bold; display:none" id="errors"></span><span style="display:none; font-weight:bold; color:green" id="applied">&ensp;Изменения внесены</span></div>
</div>
</div>
</form>

View file

@ -0,0 +1,161 @@
<?php
use \App\Services\{DB, Auth, Date};
$sessions = DB::query('SELECT * FROM login_tokens WHERE user_id=:uid', array(':uid'=>Auth::userid()));
foreach ($sessions as $session) {
try {
$iv = $session['iv'];
$decryptedIp = openssl_decrypt($session['ip'], 'AES-256-CBC', NGALLERY['root']['encryptionkey'], 0, $iv);
$decryptedLoc = openssl_decrypt($session['location'], 'AES-256-CBC', NGALLERY['root']['encryptionkey'], 0, $iv);
} catch (Exception $e) {
$decryptedIp = 'Ошибка дешифровки';
$decryptedLoc = 'Ошибка дешифровки';
}
$is_current = ($session['token'] === $current_token);
echo '<div class="session-card'.($is_current ? ' current' : '').'">';
echo '<div class="card-header">';
echo '<div class="device-info">';
echo '<svg class="device-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 1H7c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 18H7V5h10v14z"/></svg>';
echo '<div class="device-meta">';
echo '<h3>'.htmlspecialchars($session['device_name']).'</h3>';
echo '<p class="os-version">'.htmlspecialchars($session['os']).'</p>';
echo '</div>';
echo '</div>';
echo '<div class="session-status">'.($is_current ? 'Текущая сессия' : '').'</div>';
echo '</div>';
echo '<div class="card-details">';
echo '<div class="detail-item">';
echo '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg>';
echo htmlspecialchars($decryptedLoc);
echo '</div>';
echo '<div class="detail-item">';
echo '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/></svg>';
echo htmlspecialchars($decryptedIp);
echo '</div>';
echo '<div class="detail-item">';
echo '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm-.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg>';
echo Date::zmdate($session['last_activity']);
echo '</div>';
echo '</div>';
if (!$is_current) {
echo '<form method="POST" class="session-form">';
echo '<input type="hidden" name="token" value="'.$session['token'].'">';
echo '<button type="submit" name="delete" class="delete-btn">';
echo '<svg class="trash-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>';
echo 'Завершить сессию';
echo '</button>';
echo '</form>';
}
echo '</div>';
}
?>
<style>
/* Базовые стили */
.session-card {
background: #fff;
border-radius: 12px;
box-shadow: 0 3px 6px rgba(0,0,0,0.05);
padding: 18px;
margin: 15px 0;
transition: all 0.3s ease;
border: 1px solid #eee;
position: relative;
}
.session-card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0,0,0,0.1);
}
/* Иконки */
.device-icon, .icon {
width: 20px;
height: 20px;
margin-right: 10px;
vertical-align: middle;
fill: #5f6368;
}
.trash-icon {
width: 18px;
height: 18px;
margin-right: 8px;
fill: #fff;
}
/* Заголовок карточки */
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.device-info {
display: flex;
align-items: center;
}
.device-meta h3 {
margin: 0;
font-size: 17px;
color: #202124;
}
.os-version {
margin: 3px 0 0;
font-size: 14px;
color: #80868b;
}
/* Детали сессии */
.card-details {
display: grid;
gap: 12px;
margin-bottom: 15px;
}
.detail-item {
display: flex;
align-items: center;
font-size: 14px;
color: #5f6368;
}
/* Кнопка удаления */
.delete-btn {
background: #dc3545;
color: white;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
display: inline-flex;
align-items: center;
transition: background 0.2s;
}
.delete-btn:hover {
background: #bb2d3b;
}
/* Статус сессии */
.session-status {
font-size: 13px;
color: #34a853;
background: #e8f6ef;
padding: 4px 10px;
border-radius: 15px;
}
/* Текущая сессия */
.session-card.current {
border-left: 4px solid #4285f4;
background: #f8f9fe;
}
</style>

View file

@ -20,25 +20,25 @@ $user = new User(Auth::userid());
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/blazeface"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs" data-restart></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/blazeface" data-restart> </script>
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" />
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<script src="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Cesium.js"></script>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" data-restart></script>
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js" data-restart></script>
<script src="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Cesium.js" data-restart></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.83/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-indoor/0.4.2/leaflet.indoor.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-indoor/0.4.2/leaflet.indoor.min.js" data-restart></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet-indoor/0.4.2/leaflet.indoor.min.css" />
<!-- Подключение плагина Leaflet.markercluster -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js" data-restart></script>
<!-- Подключение плагина Leaflet-Geoman -->
<link rel="stylesheet" href="https://unpkg.com/leaflet-geoman-free/dist/leaflet-geoman.css">
<script src="https://unpkg.com/leaflet-geoman-free/dist/leaflet-geoman.min.js"></script>
<script src="https://unpkg.com/leaflet-geoman-free/dist/leaflet-geoman.min.js" data-restart></script>
<!-- Подключение плагина Leaflet-3d-model -->
<script src="https://unpkg.com/leaflet-3d-model/dist/leaflet-3d-model.min.js"></script>
<script src="https://unpkg.com/leaflet-3d-model/dist/leaflet-3d-model.min.js" data-restart></script>
<script>
var pub_pid = 0;
</script>
@ -310,7 +310,7 @@ $user = new User(Auth::userid());
<script>
<script data-restart>
const imageUpload = document.getElementById('image');
const inputFieldsContainer = document.getElementById('inputFields');
@ -727,7 +727,7 @@ $user = new User(Auth::userid());
<td></td>
</tr>
</tbody></table>
<script>
<script data-restart>
function openViewSelector(val, el, twoside)
{
@ -923,7 +923,7 @@ $(document).ready(function()
</tr>
</tbody>
<script>
<script data-restart>
var map = L.map('map_canvas').setView([55.7558, 37.6176], 13);
var marker;
var geocoder;
@ -1232,32 +1232,7 @@ $(document).ready(function()
clear: both;
}
</style>
<tr>
<td></td>
<td style="padding:20px 2px 12px">
<button id="submitbtn" href="#" class="progress-button" data-loading="Идёт загрузка..." data-finished="Обработка..." type="submit">Опубликовать</button> &nbsp; &nbsp;&nbsp;
<span id="statusbox" class="narrow" style="font-size:20px; font-weight:bold; position:relative; top:-12px"></span>
<div id="errorsbox" style="display:none; color:red; margin-top:15px; font-weight:bold;"></div>
<div style="margin-top: 20px; max-width: 50% !important;" id="prgb" class="w3-light-grey">
</div>
</td>
</tr>
</tbody>
</table>
</form>
</div><br>
<div id="loadtable" class="p20" style="display:none; padding-bottom:20px; margin-bottom:15px">
<h4>Загруженные фотографии</h4>
<div id="loadbox" style="display:flex; flex-wrap:wrap; gap:10px"></div>
</div>
</td>
</tr>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
<script>
<script >
$('#mform').submit(function(e) {
@ -1390,6 +1365,31 @@ $(document).ready(function()
});
</script>
<tr>
<td></td>
<td style="padding:20px 2px 12px">
<button id="submitbtn" href="#" class="progress-button" data-loading="Идёт загрузка..." data-finished="Обработка..." type="submit">Опубликовать</button> &nbsp; &nbsp;&nbsp;
<span id="statusbox" class="narrow" style="font-size:20px; font-weight:bold; position:relative; top:-12px"></span>
<div id="errorsbox" style="display:none; color:red; margin-top:15px; font-weight:bold;"></div>
<div style="margin-top: 20px; max-width: 50% !important;" id="prgb" class="w3-light-grey">
</div>
</td>
</tr>
</tbody>
</table>
</form>
</div><br>
<div id="loadtable" class="p20" style="display:none; padding-bottom:20px; margin-bottom:15px">
<h4>Загруженные фотографии</h4>
<div id="loadbox" style="display:flex; flex-wrap:wrap; gap:10px"></div>
</div>
</td>
</tr>
<tr>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
</tr>
</table>
</body>
</html>

View file

@ -19,43 +19,6 @@ if (Auth::userid() > 0) {
<body>
<div id="backgr"></div>
<table class="tmain">
<style>
.styled-input {
position: relative;
margin: 20px 0;
}
.styled-input input {
width: 100%;
padding: 10px 10px 10px 0;
font-size: 16px;
border: none;
border-bottom: 2px solid #ccc;
background: transparent;
outline: none;
}
.styled-input input:focus {
border-bottom: 2px solid #000;
}
.styled-input label {
position: absolute;
top: 10px;
left: 0;
font-size: 16px;
color: #999;
pointer-events: none;
transition: 0.2s ease all;
}
.styled-input input:focus~label,
.styled-input input:valid~label {
top: -20px;
font-size: 12px;
color: #000;
}
</style>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<tr>
<td class="main">

View file

@ -1,44 +1,288 @@
<?php
include($_SERVER['DOCUMENT_ROOT'] . "/classes/DB.php");
include($_SERVER['DOCUMENT_ROOT'] . "/classes/Auth.php");
if (!isLoggedIn()) {
header('Location: /');
}
use \App\Services\{Auth, DB, Date};
use \App\Models\User;
function getFullUrl() {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https://" : "http://";
return $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
$fullUrl = getFullUrl();
$parsedUrl = parse_url($fullUrl);
$baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'];
$pathAndQuery = str_replace($baseUrl, '', $fullUrl);
function saveTasks() {
$filteredIds = [];
foreach ($_POST as $key => $value) {
if (strpos($key, 'rsn__') === 0) {
$id = substr($key, 5);
$filteredIds[] = $id;
}
}
if (!empty($filteredIds)) {
foreach ($filteredIds as $id) {
$val = ((int)$_POST['rsn__' . $id] === 0) ? 1 : 2;
DB::query('UPDATE tasks SET checked=:c WHERE id=:id', [':id' => $id, ':c' => $val]);
}
}
}
if (isset($_POST['approve'])) {
saveTasks();
DB::query('UPDATE applications_details SET checked=:ch WHERE category_id=:id AND user_id=:uid',
[':ch' => 1, ':id' => $_GET['id'], ':uid' => $_GET['uid']]);
} elseif (isset($_POST['decline'])) {
saveTasks();
DB::query('UPDATE applications_details SET checked=:ch WHERE category_id=:id AND user_id=:uid',
[':ch' => 2, ':id' => $_GET['id'], ':uid' => $_GET['uid']]);
}
$categoryTitle = htmlspecialchars(DB::query('SELECT title FROM categories_sub WHERE id=:id', [':id' => $_GET['id']])[0]['title']);
$isAdmin = (int)($_GET['adm'] ?? 0) === 1;
$userId = $isAdmin ? $_GET['uid'] : isLoggedIn();
$subs = DB::query('SELECT * FROM tasks WHERE category_id=:id AND user_id=:uid', [':id' => $_GET['id'], ':uid' => $userId]);
$appDetails = DB::query('SELECT * FROM applications_details WHERE user_id = :uid AND category_id = :cid',
[':uid' => $userId, ':cid' => $_GET['id']]);
$formData = $appDetails[0] ?? [
'experience' => '',
'work_days' => '[]',
'work_time_from' => '',
'work_time_to' => '',
'description' => '',
'myself' => 0
];
$workDays = json_decode($formData['work_days'], true);
?>
<!DOCTYPE html>
<html lang="ru">
<html lang="en">
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/LoadHead.php'); ?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js">
</head>
<body>
<div id="backgr"></div>
<table class="tmain">
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Navbar.php'); ?>
<td class="main">
<h1>Правила сайта</h1>
<div class="p20" style="padding:20px">
<?php
$myfile = fopen($_SERVER['DOCUMENT_ROOT'].'/config/rules.html', "r") or die("Unable to open file!");
echo fread($myfile,filesize($_SERVER['DOCUMENT_ROOT'].'/config/rules.html'));
fclose($myfile);
?>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/classes/Navbar.php'); ?>
<div class="container mt-5">
<div class="row mt-3">
<div class="col-md-3">
<?php if (!$isAdmin) : ?>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/classes/MySidebar.php'); ?>
<?php endif; ?>
</div>
<div class="col-md-9">
<form<?= $isAdmin ? ' action="' . htmlspecialchars($pathAndQuery) . '" method="post"' : ' id="subFormd"' ?>>
<div id="tsksa">
<div class="list-group services-list">
<h1><?= $categoryTitle ?></h1>
<?php foreach ($subs as $s) :
$statusIcon = match((int)$s['checked']) {
0 => '/static/svg/clock.svg',
1 => '/static/svg/success-ic.svg',
2 => '/static/svg/warning-ic.svg',
};
$sdata = DB::query('SELECT * FROM tasks WHERE id=:id', [':id' => $s['id']])[0];
$imgsd = json_decode($sdata['images']);
?>
<!-- Task Item -->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
<h5><b><?= htmlspecialchars($s['title']) ?> (€<?= htmlspecialchars($s['cost']) ?>)</b></h5>
<p><?= htmlspecialchars($s['description']) ?></p>
<div class="mb-3">
<?php if (!$isAdmin) : ?>
<a href="#" data-bs-toggle="modal" data-bs-target="#delete<?= $s['id'] ?>Modal" class="text-danger me-3">Supprimer</a>
<a href="#" data-bs-toggle="modal" data-bs-target="#edit<?= $s['id'] ?>Modal">Editer</a>
<?php else : ?>
<select required name="rsn__<?= $s['id'] ?>">
<option value="">Select</option>
<option value="0">Accept</option>
<option value="1">Decline</option>
</select>
<?php endif; ?>
</div>
</div>
<img width="20" src="<?= $statusIcon ?>">
</div>
<!-- Delete Modal -->
<div class="modal fade" id="delete<?= $s['id'] ?>Modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Confirmation</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
Êtes-vous sûr de vouloir supprimer?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Non</button>
<a href="/api/deletetask.php?id=<?= $s['id'] ?>" class="btn btn-danger">Oui</a>
</div>
</div>
</div>
</div>
<!-- Модальное окно редактирования задачи -->
<?php foreach ($subs as $s) :
$sdata = DB::query('SELECT * FROM tasks WHERE id=:id', [':id' => $s['id']])[0];
$imgsd = json_decode($sdata['images']);
?>
<div class="modal fade" id="edit<?= $s['id'] ?>Modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modifier le service</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="subFormED<?= $s['id'] ?>">
<div class="modal-body">
<input type="hidden" name="taskid" value="<?= $s['id'] ?>">
<div class="mb-3">
<label class="form-label">Titre</label>
<input type="text" class="form-control" name="serviceName"
value="<?= htmlspecialchars($sdata['title']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Coût</label>
<div class="input-group">
<input type="number" class="form-control" name="serviceCost"
value="<?= htmlspecialchars($sdata['cost']) ?>">
<span class="input-group-text"></span>
<select name="serviceCostUnit" class="form-select">
<option value="за услугу" <?= $sdata['unit'] === 'за услугу' ? 'selected' : '' ?>>Par service</option>
<option value="за час" <?= $sdata['unit'] === 'за час' ? 'selected' : '' ?>>Par heure</option>
</select>
</div>
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox"
id="negotiable<?= $s['id'] ?>" <?= $sdata['negotiable'] ? 'checked' : '' ?>>
<label class="form-check-label" for="negotiable<?= $s['id'] ?>">
Négociable
</label>
</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea class="form-control" name="serviceDescription" rows="3"
><?= htmlspecialchars($sdata['description']) ?></textarea>
</div>
<div class="mb-3">
<label class="form-label">Photos</label>
<div class="row row-cols-4">
<?php for ($i = 0; $i < 4; $i++) : ?>
<div class="col">
<label class="upload-btn"
style="<?= !empty($imgsd[$i]) ? "background-image: url('{$imgsd[$i]}')" : '' ?>">
<input type="file" class="upload-input"
name="serviceImages[]"
onchange="previewImage(event, this)">
<i class="bi bi-plus-lg"></i>
</label>
</div>
<?php endfor; ?>
</div>
</div>
</div>
</td>
</tr>
<tr>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-primary">Sauvegarder</button>
</div>
</form>
</div>
</div>
</div>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/views/components/Footer.php'); ?>
<script>
// JavaScript обработчик для формы редактирования
document.getElementById('subFormED<?= $s['id'] ?>').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('/api/edittask.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if(data.success) {
bootstrap.Modal.getInstance(document.getElementById('edit<?= $s['id'] ?>Modal')).hide();
window.location.reload();
}
})
.catch(error => console.error('Error:', error));
});
</script>
<?php endforeach; ?>
</div>
</div>
</form>
<!-- Вторая форма (About Specialization) -->
<form id="subFormdd" method="post">
<h4 class="mt-5">A propos de la spécialisation</h4>
<?php if ($appDetails && $appDetails[0]['checked'] === 0 && !$isAdmin) : ?>
<div class="alert alert-warning">
Ваши данные на модерации
</div>
<?php endif; ?>
</tr>
</table>
<div class="mb-3">
<label class="form-label">Expérience</label>
<select class="form-select" name="experience">
<?php for ($i = 0; $i <= 11; $i++) : ?>
<option value="<?= $i ?>" <?= $i == $formData['experience'] ? 'selected' : '' ?>>
<?= $i === 11 ? '10+ années' : ($i === 0 ? '—' : "$i année") ?>
</option>
<?php endfor; ?>
</select>
</div>
<!-- Полное содержимое второй формы -->
<?php if ($isAdmin) : ?>
<div class="mb-3">
<button type="submit" name="approve" class="btn btn-primary">Approve</button>
<button type="submit" name="decline" class="btn btn-danger">Decline</button>
</div>
<?php else : ?>
<button type="submit" class="btn btn-primary">Économiser</button>
<?php endif; ?>
</form>
</div>
</div>
<!-- New Service Modal -->
<div class="modal fade" id="newServiceModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<!-- Полное содержимое модального окна нового сервиса -->
</div>
</div>
</div>
</div>
<!-- Все скрипты из оригинала -->
<script>
$(document).ready(function() {
$('#multiple-select-field').select2({
theme: "bootstrap-5",
closeOnSelect: false
});
});
</script>
</body>
</html>

View file

@ -282,18 +282,7 @@ use App\Services\{Router, Auth};
</style>
<tr>
<td class="main">
<div class="player">
<button id="playPause"></button>
<div class="info">
<strong>Неизвестен</strong> Tele 2 - X_й дозвонишься.mp3
</div>
<div class="progress" id="progressBar">
<span></span>
<div class="slider" id="slider"></div>
</div>
<span class="time" id="time">00:00 / 00:06</span>
</div>
<audio id="audio" src="/static/kolya.mp3"></audio>
<script>
const audio = document.getElementById("audio");