modules and payments management, bug fixes

This commit is contained in:
Ivan
2024-01-21 01:09:36 +03:00
parent 983a579dc8
commit fdd2308437
13 changed files with 1853 additions and 52 deletions

View File

@@ -208,10 +208,17 @@
<h2>детали при нажатии</h2>
</div>
</div>
{{#if Paid}}
<table id="paidTable">
<tbody>
</tbody>
</table>
</table>
{{else}}
<div class="empty-span-area">
<span class="empty-span">Ещё ни один счёт не оплачен</span>
</div>
{{/if}}
</div>
<div class="payments-table-section">
@@ -233,10 +240,17 @@
<h2>нажмите на счет чтобы скачать</h2>
</div>
</div>
{{#if NotPaid}}
<table id="notPaidTable">
<tbody>
</tbody>
</table>
</table>
{{else}}
<div class="empty-span-area">
<span class="empty-span">Не оплаченные счета не найдены</span>
</div>
{{/if}}
</div>
</div>

View File

@@ -203,23 +203,29 @@
</div>
</div>
<div class="progress-update-table">
{{#if Releases}}
<table>
<tbody>
{{#each Releases}}
<tr>
<td>
<div class="row-container">
<div class="row-content">
<h1>{{this.body}}</h1>
<h2>{{this.published_at}}</h2>
<span>нет приложений</span>
</div>
<tbody>
{{#each Releases}}
<tr>
<td>
<div class="row-container">
<div class="row-content">
<h1>{{this.body}}</h1>
<h2>{{this.published_at}}</h2>
<span>нет приложений</span>
</div>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</td>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
<div class="empty-span-area full">
<span class="empty-span">История обновлений пуста</span>
</div>
{{/if}}
</div>
</div>
@@ -242,10 +248,18 @@
<h2>функции сайта в модулях</h2>
</div>
</div>
{{#if Modules}}
<table id="modules-table">
<tbody>
</tbody>
</table>
</table>
{{else}}
<div class="empty-span-area">
<span class="empty-span">Модули ещё не созданы</span>
</div>
{{/if}}
</div>
</div>

View File

@@ -0,0 +1,455 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Настройка модулей</title>
<link rel="icon" type="image/x-icon" href="../../../img/favicon.png">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<link rel="stylesheet" href="../../../styles/main.css">
<script src="../../../scripts/jquery.min.js"></script>
<script>
const API_SERVER = "{{API_SERVER}}";
</script>
<script type="module">
import { minidenticonSvg } from 'https://cdn.jsdelivr.net/npm/minidenticons@4.2.0/minidenticons.min.js'
</script>
<script src="../../../scripts/projects.js"></script>
</head>
<body>
<header class="lk-header">
<div class="header-logo">
<a href="/projects"><img src="../../../img/krbl.svg">{{#if Project.maraku}} X <img onclick="window.open('https://maraku.ru/', '_blank')" src="../../../img/maraku.svg">{{/if}}</a>
<span class="slash">/</span>
<span>{{Project.displayname}}</span>
<div class="dropdown">
<button id="headerProjects" type="button" onclick="toggleProjects();">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="18" viewBox="0 0 13 18" fill="none">
<path d="M6.93296 0.392929C6.70015 0.392929 6.49422 0.48226 6.31514 0.660923L1.20253 5.55627C1.06822 5.69026 0.969727 5.87786 0.969727 6.13691C0.969727 6.60146 1.31892 6.95876 1.78452 6.95876C1.9815 6.95876 2.1964 6.9052 2.38442 6.7176L6.93296 2.27782L11.4725 6.7176C11.6695 6.89623 11.8754 6.95876 12.0724 6.95876C12.538 6.95876 12.8872 6.60146 12.8872 6.13691C12.8872 5.87786 12.7977 5.69026 12.6544 5.55627L7.5418 0.660923C7.36271 0.48226 7.15679 0.392929 6.93296 0.392929ZM6.93296 17.5981C7.15679 17.5981 7.36271 17.4999 7.5418 17.3302L12.6544 12.4348C12.7977 12.2918 12.8872 12.1132 12.8872 11.8452C12.8872 11.3807 12.538 11.0323 12.0724 11.0323C11.8754 11.0323 11.6695 11.0948 11.4725 11.2735L6.93296 15.7132L2.38442 11.2735C2.1964 11.0859 1.9815 11.0323 1.78452 11.0323C1.31892 11.0323 0.969727 11.3807 0.969727 11.8452C0.969727 12.1132 1.06822 12.2918 1.20253 12.4348L6.31514 17.3302C6.49422 17.4999 6.70015 17.5981 6.93296 17.5981Z" fill="black" fill-opacity="0.6"/>
</svg>
</button>
<div id="dropdownProjects" class="dropdown-projects">
<input type="text" placeholder="Найти проект...">
<h1>Проекты</h1>
{{#each Projects}}
<div onclick="location.href='/project/{{this.name}}'" id="project-{{this.id}}" class="project"> {{#if this.avatar}} <div class="avatar-container"><img src="{{../API_SERVER}}/{{this.avatar}}"></div>{{/if}} {{this.displayname}}
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 20 20">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".6" d="M7.388 20c.487 0 .873-.215 1.145-.635L19.24 2.505c.204-.33.283-.579.283-.84 0-.623-.408-1.03-1.031-1.03-.453 0-.703.147-.975.577L7.343 17.428l-5.28-6.912c-.284-.397-.567-.556-.975-.556C.442 9.96 0 10.402 0 11.025c0 .261.113.556.329.828l5.88 7.49c.34.442.692.657 1.18.657Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h19.524v20H0z"/>
</clipPath>
</defs>
</svg>
</div>
{{/each}}
</div>
</div>
</div>
<nav>
<a onclick="alert('Этот раздел в разработке.');">Новости</a>
<a onclick="alert('Этот раздел в разработке.');">Помощь</a>
<div class="user">
<svg class="user-svg ring" width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 16.8241C0 17.5978 0.593536 18.1066 1.60042 18.1066H6.07316C6.15794 20.1522 7.75836 21.9434 9.99473 21.9434C12.2416 21.9434 13.8421 20.1627 13.9269 18.1066H18.3996C19.3959 18.1066 20 17.5978 20 16.8241C20 15.7642 18.9189 14.8103 18.0074 13.867C17.3079 13.1357 17.1171 11.6307 17.0323 10.4118C16.9581 6.23586 15.8771 3.54376 13.0578 2.52627C12.6974 1.13782 11.5633 0.0461426 9.99473 0.0461426C8.43668 0.0461426 7.29201 1.13782 6.94224 2.52627C4.12295 3.54376 3.04187 6.23586 2.96768 10.4118C2.88288 11.6307 2.69211 13.1357 1.99258 13.867C1.07048 14.8103 0 15.7642 0 16.8241ZM2.05618 16.5061V16.379C2.24695 16.0716 2.88288 15.4462 3.43403 14.8315C4.19714 13.9836 4.55748 12.6164 4.6529 10.5496C4.73769 5.9179 6.11553 4.44465 7.92793 3.94652C8.19292 3.88292 8.3413 3.75574 8.3519 3.48017C8.38367 2.37789 9.01963 1.60417 9.99473 1.60417C10.9804 1.60417 11.6057 2.37789 11.6481 3.48017C11.6587 3.75574 11.7965 3.88292 12.0615 3.94652C13.8845 4.44465 15.2623 5.9179 15.3471 10.5496C15.4425 12.6164 15.8029 13.9836 16.5554 14.8315C17.1171 15.4462 17.7424 16.0716 17.9332 16.379V16.5061H2.05618ZM7.72658 18.1066H12.2735C12.1887 19.548 11.2772 20.4489 9.99473 20.4489C8.72286 20.4489 7.80077 19.548 7.72658 18.1066Z" fill="black" fill-opacity="0.85"/>
</svg>
<div class="dropdown">
<minidenticon-svg onclick="toggleAccount();" id="userIcon" style="height: 40px;" username="{{User.email}}"></minidenticon-svg>
<div id="dropdownAccount" class="dropdown-account">
<div class="user-name">
<h1>{{User.name}}</h1>
<h2>{{User.email}}</h2>
</div>
<a href="/user/settings">Настройки профиля <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 18 18">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".85" d="M8.15 17.992h1.7c.647 0 1.143-.396 1.295-1.019l.362-1.573.269-.093 1.37.842c.547.345 1.178.26 1.64-.202l1.178-1.17c.463-.463.547-1.102.202-1.64l-.858-1.364.101-.253 1.573-.37A1.301 1.301 0 0 0 18 9.854V8.188c0-.64-.395-1.145-1.018-1.296l-1.556-.379-.11-.269.859-1.363c.345-.539.26-1.17-.202-1.641l-1.178-1.178c-.454-.455-1.085-.539-1.631-.202l-1.371.841-.286-.11-.362-1.573C10.993.396 10.497 0 9.85 0h-1.7c-.647 0-1.143.396-1.295 1.018l-.37 1.574-.286.11-1.363-.842c-.546-.337-1.186-.253-1.64.202L2.027 3.24c-.463.471-.555 1.102-.202 1.64l.85 1.364-.101.27-1.556.378A1.293 1.293 0 0 0 0 8.188v1.666a1.3 1.3 0 0 0 1.018 1.296l1.573.37.092.253-.85 1.363c-.353.539-.26 1.178.203 1.641l1.169 1.17c.462.463 1.102.547 1.648.202l1.363-.842.269.093.37 1.573c.152.623.648 1.019 1.295 1.019Zm.135-1.313c-.143 0-.219-.06-.244-.194l-.505-2.087a4.748 4.748 0 0 1-1.354-.555L4.35 14.97c-.101.076-.21.06-.312-.042l-.992-.993c-.093-.092-.101-.193-.034-.31l1.127-1.819a6.132 6.132 0 0 1-.546-1.346l-2.086-.496c-.135-.026-.194-.101-.194-.245V8.314c0-.151.05-.219.194-.244l2.077-.505c.135-.547.387-1.043.538-1.355L3.003 4.393c-.076-.127-.067-.227.025-.328l1.001-.977c.1-.1.193-.117.32-.042L6.165 4.15a6.821 6.821 0 0 1 1.38-.556l.496-2.087c.025-.134.101-.193.244-.193h1.43c.143 0 .219.059.235.193l.514 2.104c.521.135.975.345 1.354.547l1.825-1.11c.135-.076.219-.06.328.041l.992.977c.102.1.102.201.026.328L13.87 6.21c.16.312.404.808.538 1.355l2.086.505c.135.025.194.093.194.244V9.72c0 .144-.067.22-.194.245l-2.094.496a5.75 5.75 0 0 1-.547 1.346l1.127 1.818c.068.118.068.219-.033.311l-.984.993c-.11.101-.21.118-.32.042l-1.834-1.127a4.69 4.69 0 0 1-1.345.555l-.514 2.087c-.016.135-.092.194-.235.194h-1.43ZM9 12.21c1.758 0 3.205-1.447 3.205-3.214 0-1.75-1.447-3.198-3.205-3.198S5.787 7.245 5.787 8.996A3.23 3.23 0 0 0 9 12.21Zm0-1.304a1.91 1.91 0 0 1-1.9-1.91c0-1.035.857-1.894 1.9-1.894 1.026 0 1.884.859 1.884 1.894 0 1.043-.858 1.91-1.884 1.91Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h18v18H0z"/>
</clipPath>
</defs>
</svg>
</a>
<a href="/projects">Смотреть проекты
<svg xmlns="http://www.w3.org/2000/svg" style="width: 16px !important; height: 16px !important;" width="16" height="16" fill="none" viewBox="0 0 16 16">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".85" d="M1.973 11.72a.917.917 0 0 0-.911-.925c-.494 0-.895.42-.895.925a.901.901 0 1 0 1.805 0Zm0 3.355c0-.505-.401-.933-.911-.933-.494 0-.895.428-.895.933 0 .514.401.925.895.925.51 0 .91-.41.91-.925Zm13.726-3.355c0-.377-.3-.66-.71-.66H3.736c-.41 0-.71.283-.71.66 0 .376.3.667.71.667h11.252c.41 0 .71-.29.71-.667Zm0 3.355c0-.376-.3-.659-.71-.659H3.736c-.41 0-.71.283-.71.66 0 .376.3.667.71.667h11.252c.41 0 .71-.29.71-.668ZM2.316.205C.61.205 0 .967 0 2.628v3.98C0 8.27.61 9.033 2.316 9.033h11.368C15.39 9.032 16 8.27 16 6.609v-3.98C16 .966 15.39.204 13.684.204H2.316Zm-.97 6.447V2.585c0-.762.242-1.095.978-1.095h11.352c.736 0 .978.333.978 1.095v4.067c0 .762-.242 1.095-.978 1.095H2.324c-.736 0-.978-.333-.978-1.095Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h16v16H0z"/>
</clipPath>
</defs>
</svg>
</a>
<div class="line"></div>
<div class="theme-selector">
<span>Тема</span>
<div class="theme-switcher">
<button id="light-theme-btn" class="theme-btn" onclick="setTheme('light')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M12.493 10.7193C8.11132 10.7193 5.39164 8.09866 5.39164 3.89146C5.39164 2.69166 5.59046 1.63394 5.88469 1.06561C6.00397 0.836704 6.02785 0.726195 6.02785 0.568327C6.02785 0.307844 5.7813 0 5.4473 0C5.38369 0 5.23262 0.0236803 5.00995 0.110508C2.0676 1.29453 0 4.37297 0 7.68821C0 12.4795 3.50696 15.9684 8.33398 15.9684C11.7933 15.9684 14.6004 14.1687 15.8887 11.2166C15.9841 11.0113 16 10.8377 16 10.7509C16 10.4272 15.7217 10.2062 15.4752 10.2062C15.3479 10.2062 15.2525 10.2141 15.0616 10.2851C14.4175 10.5456 13.4473 10.7193 12.493 10.7193ZM1.24851 7.63296C1.24851 5.17809 2.53678 2.84164 4.59641 1.55501C4.34196 2.2891 4.20675 3.10212 4.20675 4.00196C4.20675 8.93537 7.23658 11.8717 12.3101 11.8717C13.1292 11.8717 13.8211 11.777 14.4811 11.5481C13.2724 13.5294 10.9424 14.7371 8.3817 14.7371C4.25447 14.7371 1.24851 11.7533 1.24851 7.63296Z" fill="black" fill-opacity="0.85"/>
</svg>
</button>
<button id="dark-theme-btn" class="theme-btn" onclick="setTheme('dark')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_228_36)">
<path d="M8.0037 2.86688C8.35137 2.86688 8.63985 2.57946 8.63985 2.2257V0.641179C8.63985 0.287425 8.35137 0 8.0037 0C7.64863 0 7.36015 0.287425 7.36015 0.641179V2.2257C7.36015 2.57946 7.64863 2.86688 8.0037 2.86688ZM11.6283 4.37772C11.8798 4.62091 12.2867 4.62828 12.5381 4.37772L13.6699 3.25012C13.914 3.00691 13.914 2.5942 13.6699 2.34362C13.4258 2.10042 13.019 2.10042 12.7675 2.34362L11.6283 3.47857C11.3842 3.72915 11.3842 4.13451 11.6283 4.37772ZM13.1299 7.99633C13.1299 8.3427 13.4258 8.63014 13.7735 8.63014H15.3638C15.7115 8.63014 16 8.3427 16 7.99633C16 7.64994 15.7115 7.35513 15.3638 7.35513H13.7735C13.4258 7.35513 13.1299 7.64994 13.1299 7.99633ZM11.6283 11.6149C11.3842 11.8655 11.3842 12.2708 11.6283 12.5141L12.7675 13.6564C13.019 13.8922 13.4258 13.8849 13.6699 13.649C13.914 13.3985 13.914 12.9931 13.6699 12.7499L12.5307 11.6149C12.2867 11.3791 11.8798 11.3791 11.6283 11.6149ZM8.0037 13.1257C7.64863 13.1257 7.36015 13.4132 7.36015 13.7596V15.3515C7.36015 15.6979 7.64863 15.9853 8.0037 15.9853C8.35137 15.9853 8.63985 15.6979 8.63985 15.3515V13.7596C8.63985 13.4132 8.35137 13.1257 8.0037 13.1257ZM4.3717 11.6149C4.12019 11.3791 3.70595 11.3791 3.46187 11.6149L2.3301 12.7425C2.08599 12.9857 2.08599 13.3911 2.3227 13.6416C2.56681 13.8775 2.98105 13.8849 3.23253 13.649L4.36431 12.5141C4.60843 12.2708 4.60843 11.8655 4.3717 11.6149ZM2.87009 7.99633C2.87009 7.64994 2.5742 7.35513 2.22654 7.35513H0.636154C0.288488 7.35513 0 7.64994 0 7.99633C0 8.3427 0.288488 8.63014 0.636154 8.63014H2.22654C2.5742 8.63014 2.87009 8.3427 2.87009 7.99633ZM4.36431 4.37772C4.60843 4.14187 4.60843 3.72179 4.3717 3.47857L3.23996 2.34362C2.99584 2.10779 2.5816 2.10042 2.33749 2.34362C2.09339 2.5942 2.09339 3.00691 2.3301 3.24275L3.46187 4.37772C3.70595 4.62091 4.1128 4.62091 4.36431 4.37772Z" fill="black" fill-opacity="0.85"/>
<path d="M7.99611 11.755C10.0525 11.755 11.7613 10.0525 11.7613 7.99636C11.7613 5.93277 10.0525 4.23035 7.99611 4.23035C5.93971 4.23035 4.23096 5.93277 4.23096 7.99636C4.23096 10.0525 5.93971 11.755 7.99611 11.755ZM7.99611 10.6274C6.55368 10.6274 5.35534 9.43347 5.35534 7.99636C5.35534 6.55185 6.55368 5.35792 7.99611 5.35792C9.43854 5.35792 10.6369 6.55185 10.6369 7.99636C10.6369 9.43347 9.43854 10.6274 7.99611 10.6274Z" fill="black" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_228_36">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
</button>
<button id="system-theme-btn" class="theme-btn" onclick="setTheme('system')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_228_46)">
<path d="M1.54362 13.2758H14.4497C15.4161 13.2758 16 12.6082 16 11.5031V2.30216C16 1.19712 15.4161 0.53717 14.4497 0.53717H1.54362C0.583892 0.53717 0 1.19712 0 2.30216V11.5031C0 12.6082 0.583892 13.2758 1.54362 13.2758ZM1.56376 12.0403C1.26846 12.0403 1.08054 11.8254 1.08054 11.4878V2.32518C1.08054 1.97986 1.26846 1.77266 1.56376 1.77266H14.4362C14.7316 1.77266 14.9195 1.97986 14.9195 2.32518V11.4878C14.9195 11.8254 14.7316 12.0403 14.4362 12.0403H1.56376ZM5.87919 15.1022H10.1208V13.176H5.87919V15.1022ZM5.83892 16H10.1611C10.4564 16 10.698 15.7237 10.698 15.3784C10.698 15.0331 10.4564 14.7568 10.1611 14.7568H5.83892C5.54362 14.7568 5.29531 15.0331 5.29531 15.3784C5.29531 15.7237 5.54362 16 5.83892 16Z" fill="black" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_228_46">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
</button>
</div>
</div>
<div class="line"></div>
<a href="/" target="_blank">Главная страница
<svg data-testid="geist-icon" fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24" style="width: 20px; height: 20px;"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></svg>
</a>
<a href="/logout">Выйти из аккаунта</a>
<div class="line"></div>
<button onclick="location.href='/'" class="button">Связаться с нами</button>
</div>
</div>
</div>
</nav>
</header>
<nav class="sections">
<a href="/project/{{Name}}">Обзор</a>
<a href="/project/{{Name}}/progress">Прогресс</a>
<a href="/project/{{Name}}/documents">Документы</a>
<a href="/project/{{Name}}/payments">Оплата</a>
<a href="/project/{{Name}}/tests">Тесты</a>
{{#if IsAdmin}}
<a class="selected" href="/project/{{Name}}/settings">Настройки</a>
{{/if}}
</nav>
<div class="notifications"></div>
<section class="content-bg">
<div class="progress-name-section">
<h1>Настройки проекта</h1>
<h2>Здесь можно изменить основную информацию и обновить фотокарточки проекта.</h2>
</div>
<div class="settings-content">
<nav class="settings-sections">
<a href="/project/{{Name}}/settings">Основные</a>
<a class="selected" href="/project/{{Name}}/settings/modules">Модули</a>
<a href="/project/{{Name}}/settings/payments">Платежи</a>
</nav>
<div style="width: 100%;" class="table-search-section">
<input type="text" class="add-input" id="add-name" placeholder="Название нового модуля...">
<input type="number" id="add-procent" placeholder="Процент готовности">
<button onclick="addModule();" id="addModule" class="upload-button"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15" fill="none">
<g clip-path="url(#clip0_368_7)">
<path d="M0 7.49546C0 7.94065 0.372729 8.30408 0.80909 8.30408H6.69093V14.1823C6.69093 14.6184 7.05454 14.9909 7.5 14.9909C7.94546 14.9909 8.31819 14.6184 8.31819 14.1823V8.30408H14.1909C14.6273 8.30408 15 7.94065 15 7.49546C15 7.05027 14.6273 6.67776 14.1909 6.67776H8.31819V0.808601C8.31819 0.372503 7.94546 0 7.5 0C7.05454 0 6.69093 0.372503 6.69093 0.808601V6.67776H0.80909C0.372729 6.67776 0 7.05027 0 7.49546Z" fill="white" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_368_7">
<rect width="15" height="15" fill="white"/>
</clipPath>
</defs>
</svg>
Добавить модуль</button>
</div>
{{#each Modules}}
<div id="module-{{this.id}}" class="setting-section">
<div class="setting-top">
<h2>Название</h2>
<input oninput="handleInputChange(this)" id="modulename-input" type="text" value="{{this.name}}" required>
<h2>Процент готовности</h2>
<input onchange="handleProcentChange(event)" oninput="updateProgressBar(this)" id="moduleprocent-input" type="number" class="input-progress" value="{{this.procent}}" required>
<div class="progress-bar" data-progress="{{this.procent}}">
<div style="width: 0;" class="progress-fill"></div>
</div>
</div>
<div class="setting-bottom">
<h2>Используйте максимум 32 символа.</h2>
<div class="buttons">
<button id="deleteModule{{this.id}}" class="delete" type="button" onclick="deleteModule({{this.id}});">Удалить</button>
<button id="updateModule{{this.id}}" class="updateButton" type="button" onclick="updateModule({{this.id}})">Сохранить</button>
</div>
</div>
</div>
{{/each}}
</div>
</section>
<script>
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("project-{{Project.id}}").classList.add("selected");
var progressBars = document.querySelectorAll('.progress-bar');
progressBars.forEach(function(progressBar) {
var progressFill = progressBar.querySelector('.progress-fill');
var progressValue = parseInt(progressBar.dataset.progress, 10);
progressFill.style.width = progressValue + '%';
});
});
</script>
<script src="../../../scripts/notifications.js"></script>
<script>
function handleInputChange(input) {
const settingBottom = input.parentElement.nextElementSibling;
const button = settingBottom.querySelector('.updateButton');
button.classList.remove('inactive');
}
function getCookie(name) {
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.startsWith(name + "=")) {
return cookie.substring(name.length + 1);
}
}
return null;
}
</script>
<script>
function toggleProjects() {
if ($('#dropdownProjects').hasClass('is-visible')) {
event.preventDefault();
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
} else {
event.preventDefault();
$("#dropdownProjects").css("display", "inline-flex");
$('#dropdownProjects').addClass('is-visible');
}
}
$(document).on('click', function(event) {
if ($(event.target).closest('#headerProjects').length) {
return;
} else {
if (!$(event.target).closest('.dropdown-projects').length) {
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
}
}
});
$(document).ready(function() {
$(document).keydown(function(e) {
if (e.key === "Escape" || e.key === "Esc") {
console.log("Escape")
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
}
});
});
function updateProgressBar(input) {
const settingBottom = input.parentElement.nextElementSibling;
const button = settingBottom.querySelector('.updateButton');
button.classList.remove('inactive');
const value = input.value;
const clampedValue = Math.min(100, Math.max(0, value));
const progressBar = input.nextElementSibling.querySelector('.progress-fill');
const fillWidth = clampedValue + '%';
progressBar.style.width = fillWidth;
}
function handleProcentChange(event) {
let inputValue = parseFloat(event.target.value);
if (isNaN(inputValue)) {
console.error("Введите числовое значение");
return;
}
inputValue = Math.max(0, Math.min(inputValue, 100));
event.target.value = inputValue;
}
</script>
<script>
async function addModule() {
$(`#addModule`).addClass("inactive");
$(`#addModule`).blur();
const project = '{{Project.name}}';
const name = $("#add-name").val();
const procent = $("#add-procent").val();
if (!name) {
alert("Введите название модуля.");
$(`#addModule`).removeClass("inactive");
return;
}
const response = await fetch("{{API_SERVER}}/module", {
method: "POST",
headers: {
Authorization: getCookie("token"),
"Content-Type": "application/json"
},
body: JSON.stringify({ project, name, procent })
});
if (response.status === 201) {
const responseData = await response.json();
const moduleId = responseData.data.id;
const name = responseData.data.name;
const procent = responseData.data.procent;
const newModuleHtml = `
<div id="module-${moduleId}" class="setting-section">
<div class="setting-top">
<h2>Название</h2>
<input oninput="handleInputChange(this)" id="modulename-input" type="text" value="${name}" required>
<h2>Процент готовности</h2>
<input onchange="handleProcentChange(event)" oninput="updateProgressBar(this)" id="moduleprocent-input" type="number" class="input-progress" value="${procent}" required>
<div class="progress-bar" data-progress="${procent}">
<div style="width: 0;" class="progress-fill"></div>
</div>
</div>
<div class="setting-bottom">
<h2>Используйте максимум 32 символа.</h2>
<div class="buttons">
<button id="deleteModule${moduleId}" class="delete" type="button" onclick="deleteModule(${moduleId});">Удалить</button>
<button id="updateModule${moduleId}" class="updateButton" type="button" onclick="updateModule(${moduleId})">Сохранить</button>
</div>
</div>
</div>
`;
$(".settings-content").children().eq(1).after(newModuleHtml);
$(`#module-${moduleId} .progress-fill`).css("width", `${procent}%`);
notis.create(
"Модуль добавлен!",
"Модуль успешно добавлен и доступен в списке для дальнейших действий",
5
);
$(`#addModule`).removeClass("inactive");
} else {
alert("Ошибка при добавлении модуля.");
}
}
async function deleteModule(id) {
$(`#deleteModule${id}`).addClass("inactive");
$(`#deleteModule${id}`).blur();
const response = await fetch("{{API_SERVER}}/module?id=" + id, {
method: "DELETE",
headers: {
Authorization: getCookie("token"),
"Content-Type": "application/json"
}
});
if (response.status === 200) {
const $block = $(`#module-${id}`);
$block.addClass('hidden').animate({height: 0}, 500, function(){
$block.remove();
});
} else {
alert("Ошибка при добавлении модуля.");
}
}
async function updateModule(id) {
$(`#updateModule${id}`).addClass("inactive");
$(`#updateModule${id}`).blur();
const project = '{{Project.name}}';
const name = $(`#module-${id} #modulename-input`).val();
const procent = $(`#module-${id} #moduleprocent-input`).val();
const response = await fetch("{{API_SERVER}}/module", {
method: "PUT",
headers: {
Authorization: getCookie("token"),
"Content-Type": "application/json"
},
body: JSON.stringify({ project, name, procent, id })
});
if (response.status === 200) {
notis.create(
"Модуль обновлен",
"Данные модуля успешно обновлены!",
5
);
$(`#updateModule${id}`).removeClass("inactive");
} else {
alert("Ошибка при обновлении модуля.");
}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,530 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Настройка платежей</title>
<link rel="icon" type="image/x-icon" href="../../../../img/favicon.png">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<link rel="stylesheet" href="../../../../styles/main.css">
<script src="../../../../scripts/jquery.min.js"></script>
<script>
const API_SERVER = "{{API_SERVER}}";
</script>
<script type="module">
import { minidenticonSvg } from 'https://cdn.jsdelivr.net/npm/minidenticons@4.2.0/minidenticons.min.js'
</script>
<script src="../../../../scripts/projects.js"></script>
</head>
<body>
<header class="lk-header">
<div class="header-logo">
<a href="/projects"><img src="../../../../img/krbl.svg">{{#if Project.maraku}} X <img onclick="window.open('https://maraku.ru/', '_blank')" src="../../../../img/maraku.svg">{{/if}}</a>
<span class="slash">/</span>
<span>{{Project.displayname}}</span>
<div class="dropdown">
<button id="headerProjects" type="button" onclick="toggleProjects();">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="18" viewBox="0 0 13 18" fill="none">
<path d="M6.93296 0.392929C6.70015 0.392929 6.49422 0.48226 6.31514 0.660923L1.20253 5.55627C1.06822 5.69026 0.969727 5.87786 0.969727 6.13691C0.969727 6.60146 1.31892 6.95876 1.78452 6.95876C1.9815 6.95876 2.1964 6.9052 2.38442 6.7176L6.93296 2.27782L11.4725 6.7176C11.6695 6.89623 11.8754 6.95876 12.0724 6.95876C12.538 6.95876 12.8872 6.60146 12.8872 6.13691C12.8872 5.87786 12.7977 5.69026 12.6544 5.55627L7.5418 0.660923C7.36271 0.48226 7.15679 0.392929 6.93296 0.392929ZM6.93296 17.5981C7.15679 17.5981 7.36271 17.4999 7.5418 17.3302L12.6544 12.4348C12.7977 12.2918 12.8872 12.1132 12.8872 11.8452C12.8872 11.3807 12.538 11.0323 12.0724 11.0323C11.8754 11.0323 11.6695 11.0948 11.4725 11.2735L6.93296 15.7132L2.38442 11.2735C2.1964 11.0859 1.9815 11.0323 1.78452 11.0323C1.31892 11.0323 0.969727 11.3807 0.969727 11.8452C0.969727 12.1132 1.06822 12.2918 1.20253 12.4348L6.31514 17.3302C6.49422 17.4999 6.70015 17.5981 6.93296 17.5981Z" fill="black" fill-opacity="0.6"/>
</svg>
</button>
<div id="dropdownProjects" class="dropdown-projects">
<input type="text" placeholder="Найти проект...">
<h1>Проекты</h1>
{{#each Projects}}
<div onclick="location.href='/project/{{this.name}}'" id="project-{{this.id}}" class="project"> {{#if this.avatar}} <div class="avatar-container"><img src="{{../API_SERVER}}/{{this.avatar}}"></div>{{/if}} {{this.displayname}}
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 20 20">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".6" d="M7.388 20c.487 0 .873-.215 1.145-.635L19.24 2.505c.204-.33.283-.579.283-.84 0-.623-.408-1.03-1.031-1.03-.453 0-.703.147-.975.577L7.343 17.428l-5.28-6.912c-.284-.397-.567-.556-.975-.556C.442 9.96 0 10.402 0 11.025c0 .261.113.556.329.828l5.88 7.49c.34.442.692.657 1.18.657Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h19.524v20H0z"/>
</clipPath>
</defs>
</svg>
</div>
{{/each}}
</div>
</div>
</div>
<nav>
<a onclick="alert('Этот раздел в разработке.');">Новости</a>
<a onclick="alert('Этот раздел в разработке.');">Помощь</a>
<div class="user">
<svg class="user-svg ring" width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 16.8241C0 17.5978 0.593536 18.1066 1.60042 18.1066H6.07316C6.15794 20.1522 7.75836 21.9434 9.99473 21.9434C12.2416 21.9434 13.8421 20.1627 13.9269 18.1066H18.3996C19.3959 18.1066 20 17.5978 20 16.8241C20 15.7642 18.9189 14.8103 18.0074 13.867C17.3079 13.1357 17.1171 11.6307 17.0323 10.4118C16.9581 6.23586 15.8771 3.54376 13.0578 2.52627C12.6974 1.13782 11.5633 0.0461426 9.99473 0.0461426C8.43668 0.0461426 7.29201 1.13782 6.94224 2.52627C4.12295 3.54376 3.04187 6.23586 2.96768 10.4118C2.88288 11.6307 2.69211 13.1357 1.99258 13.867C1.07048 14.8103 0 15.7642 0 16.8241ZM2.05618 16.5061V16.379C2.24695 16.0716 2.88288 15.4462 3.43403 14.8315C4.19714 13.9836 4.55748 12.6164 4.6529 10.5496C4.73769 5.9179 6.11553 4.44465 7.92793 3.94652C8.19292 3.88292 8.3413 3.75574 8.3519 3.48017C8.38367 2.37789 9.01963 1.60417 9.99473 1.60417C10.9804 1.60417 11.6057 2.37789 11.6481 3.48017C11.6587 3.75574 11.7965 3.88292 12.0615 3.94652C13.8845 4.44465 15.2623 5.9179 15.3471 10.5496C15.4425 12.6164 15.8029 13.9836 16.5554 14.8315C17.1171 15.4462 17.7424 16.0716 17.9332 16.379V16.5061H2.05618ZM7.72658 18.1066H12.2735C12.1887 19.548 11.2772 20.4489 9.99473 20.4489C8.72286 20.4489 7.80077 19.548 7.72658 18.1066Z" fill="black" fill-opacity="0.85"/>
</svg>
<div class="dropdown">
<minidenticon-svg onclick="toggleAccount();" id="userIcon" style="height: 40px;" username="{{User.email}}"></minidenticon-svg>
<div id="dropdownAccount" class="dropdown-account">
<div class="user-name">
<h1>{{User.name}}</h1>
<h2>{{User.email}}</h2>
</div>
<a href="/user/settings">Настройки профиля <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 18 18">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".85" d="M8.15 17.992h1.7c.647 0 1.143-.396 1.295-1.019l.362-1.573.269-.093 1.37.842c.547.345 1.178.26 1.64-.202l1.178-1.17c.463-.463.547-1.102.202-1.64l-.858-1.364.101-.253 1.573-.37A1.301 1.301 0 0 0 18 9.854V8.188c0-.64-.395-1.145-1.018-1.296l-1.556-.379-.11-.269.859-1.363c.345-.539.26-1.17-.202-1.641l-1.178-1.178c-.454-.455-1.085-.539-1.631-.202l-1.371.841-.286-.11-.362-1.573C10.993.396 10.497 0 9.85 0h-1.7c-.647 0-1.143.396-1.295 1.018l-.37 1.574-.286.11-1.363-.842c-.546-.337-1.186-.253-1.64.202L2.027 3.24c-.463.471-.555 1.102-.202 1.64l.85 1.364-.101.27-1.556.378A1.293 1.293 0 0 0 0 8.188v1.666a1.3 1.3 0 0 0 1.018 1.296l1.573.37.092.253-.85 1.363c-.353.539-.26 1.178.203 1.641l1.169 1.17c.462.463 1.102.547 1.648.202l1.363-.842.269.093.37 1.573c.152.623.648 1.019 1.295 1.019Zm.135-1.313c-.143 0-.219-.06-.244-.194l-.505-2.087a4.748 4.748 0 0 1-1.354-.555L4.35 14.97c-.101.076-.21.06-.312-.042l-.992-.993c-.093-.092-.101-.193-.034-.31l1.127-1.819a6.132 6.132 0 0 1-.546-1.346l-2.086-.496c-.135-.026-.194-.101-.194-.245V8.314c0-.151.05-.219.194-.244l2.077-.505c.135-.547.387-1.043.538-1.355L3.003 4.393c-.076-.127-.067-.227.025-.328l1.001-.977c.1-.1.193-.117.32-.042L6.165 4.15a6.821 6.821 0 0 1 1.38-.556l.496-2.087c.025-.134.101-.193.244-.193h1.43c.143 0 .219.059.235.193l.514 2.104c.521.135.975.345 1.354.547l1.825-1.11c.135-.076.219-.06.328.041l.992.977c.102.1.102.201.026.328L13.87 6.21c.16.312.404.808.538 1.355l2.086.505c.135.025.194.093.194.244V9.72c0 .144-.067.22-.194.245l-2.094.496a5.75 5.75 0 0 1-.547 1.346l1.127 1.818c.068.118.068.219-.033.311l-.984.993c-.11.101-.21.118-.32.042l-1.834-1.127a4.69 4.69 0 0 1-1.345.555l-.514 2.087c-.016.135-.092.194-.235.194h-1.43ZM9 12.21c1.758 0 3.205-1.447 3.205-3.214 0-1.75-1.447-3.198-3.205-3.198S5.787 7.245 5.787 8.996A3.23 3.23 0 0 0 9 12.21Zm0-1.304a1.91 1.91 0 0 1-1.9-1.91c0-1.035.857-1.894 1.9-1.894 1.026 0 1.884.859 1.884 1.894 0 1.043-.858 1.91-1.884 1.91Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h18v18H0z"/>
</clipPath>
</defs>
</svg>
</a>
<a href="/projects">Смотреть проекты
<svg xmlns="http://www.w3.org/2000/svg" style="width: 16px !important; height: 16px !important;" width="16" height="16" fill="none" viewBox="0 0 16 16">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".85" d="M1.973 11.72a.917.917 0 0 0-.911-.925c-.494 0-.895.42-.895.925a.901.901 0 1 0 1.805 0Zm0 3.355c0-.505-.401-.933-.911-.933-.494 0-.895.428-.895.933 0 .514.401.925.895.925.51 0 .91-.41.91-.925Zm13.726-3.355c0-.377-.3-.66-.71-.66H3.736c-.41 0-.71.283-.71.66 0 .376.3.667.71.667h11.252c.41 0 .71-.29.71-.667Zm0 3.355c0-.376-.3-.659-.71-.659H3.736c-.41 0-.71.283-.71.66 0 .376.3.667.71.667h11.252c.41 0 .71-.29.71-.668ZM2.316.205C.61.205 0 .967 0 2.628v3.98C0 8.27.61 9.033 2.316 9.033h11.368C15.39 9.032 16 8.27 16 6.609v-3.98C16 .966 15.39.204 13.684.204H2.316Zm-.97 6.447V2.585c0-.762.242-1.095.978-1.095h11.352c.736 0 .978.333.978 1.095v4.067c0 .762-.242 1.095-.978 1.095H2.324c-.736 0-.978-.333-.978-1.095Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h16v16H0z"/>
</clipPath>
</defs>
</svg>
</a>
<div class="line"></div>
<div class="theme-selector">
<span>Тема</span>
<div class="theme-switcher">
<button id="light-theme-btn" class="theme-btn" onclick="setTheme('light')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M12.493 10.7193C8.11132 10.7193 5.39164 8.09866 5.39164 3.89146C5.39164 2.69166 5.59046 1.63394 5.88469 1.06561C6.00397 0.836704 6.02785 0.726195 6.02785 0.568327C6.02785 0.307844 5.7813 0 5.4473 0C5.38369 0 5.23262 0.0236803 5.00995 0.110508C2.0676 1.29453 0 4.37297 0 7.68821C0 12.4795 3.50696 15.9684 8.33398 15.9684C11.7933 15.9684 14.6004 14.1687 15.8887 11.2166C15.9841 11.0113 16 10.8377 16 10.7509C16 10.4272 15.7217 10.2062 15.4752 10.2062C15.3479 10.2062 15.2525 10.2141 15.0616 10.2851C14.4175 10.5456 13.4473 10.7193 12.493 10.7193ZM1.24851 7.63296C1.24851 5.17809 2.53678 2.84164 4.59641 1.55501C4.34196 2.2891 4.20675 3.10212 4.20675 4.00196C4.20675 8.93537 7.23658 11.8717 12.3101 11.8717C13.1292 11.8717 13.8211 11.777 14.4811 11.5481C13.2724 13.5294 10.9424 14.7371 8.3817 14.7371C4.25447 14.7371 1.24851 11.7533 1.24851 7.63296Z" fill="black" fill-opacity="0.85"/>
</svg>
</button>
<button id="dark-theme-btn" class="theme-btn" onclick="setTheme('dark')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_228_36)">
<path d="M8.0037 2.86688C8.35137 2.86688 8.63985 2.57946 8.63985 2.2257V0.641179C8.63985 0.287425 8.35137 0 8.0037 0C7.64863 0 7.36015 0.287425 7.36015 0.641179V2.2257C7.36015 2.57946 7.64863 2.86688 8.0037 2.86688ZM11.6283 4.37772C11.8798 4.62091 12.2867 4.62828 12.5381 4.37772L13.6699 3.25012C13.914 3.00691 13.914 2.5942 13.6699 2.34362C13.4258 2.10042 13.019 2.10042 12.7675 2.34362L11.6283 3.47857C11.3842 3.72915 11.3842 4.13451 11.6283 4.37772ZM13.1299 7.99633C13.1299 8.3427 13.4258 8.63014 13.7735 8.63014H15.3638C15.7115 8.63014 16 8.3427 16 7.99633C16 7.64994 15.7115 7.35513 15.3638 7.35513H13.7735C13.4258 7.35513 13.1299 7.64994 13.1299 7.99633ZM11.6283 11.6149C11.3842 11.8655 11.3842 12.2708 11.6283 12.5141L12.7675 13.6564C13.019 13.8922 13.4258 13.8849 13.6699 13.649C13.914 13.3985 13.914 12.9931 13.6699 12.7499L12.5307 11.6149C12.2867 11.3791 11.8798 11.3791 11.6283 11.6149ZM8.0037 13.1257C7.64863 13.1257 7.36015 13.4132 7.36015 13.7596V15.3515C7.36015 15.6979 7.64863 15.9853 8.0037 15.9853C8.35137 15.9853 8.63985 15.6979 8.63985 15.3515V13.7596C8.63985 13.4132 8.35137 13.1257 8.0037 13.1257ZM4.3717 11.6149C4.12019 11.3791 3.70595 11.3791 3.46187 11.6149L2.3301 12.7425C2.08599 12.9857 2.08599 13.3911 2.3227 13.6416C2.56681 13.8775 2.98105 13.8849 3.23253 13.649L4.36431 12.5141C4.60843 12.2708 4.60843 11.8655 4.3717 11.6149ZM2.87009 7.99633C2.87009 7.64994 2.5742 7.35513 2.22654 7.35513H0.636154C0.288488 7.35513 0 7.64994 0 7.99633C0 8.3427 0.288488 8.63014 0.636154 8.63014H2.22654C2.5742 8.63014 2.87009 8.3427 2.87009 7.99633ZM4.36431 4.37772C4.60843 4.14187 4.60843 3.72179 4.3717 3.47857L3.23996 2.34362C2.99584 2.10779 2.5816 2.10042 2.33749 2.34362C2.09339 2.5942 2.09339 3.00691 2.3301 3.24275L3.46187 4.37772C3.70595 4.62091 4.1128 4.62091 4.36431 4.37772Z" fill="black" fill-opacity="0.85"/>
<path d="M7.99611 11.755C10.0525 11.755 11.7613 10.0525 11.7613 7.99636C11.7613 5.93277 10.0525 4.23035 7.99611 4.23035C5.93971 4.23035 4.23096 5.93277 4.23096 7.99636C4.23096 10.0525 5.93971 11.755 7.99611 11.755ZM7.99611 10.6274C6.55368 10.6274 5.35534 9.43347 5.35534 7.99636C5.35534 6.55185 6.55368 5.35792 7.99611 5.35792C9.43854 5.35792 10.6369 6.55185 10.6369 7.99636C10.6369 9.43347 9.43854 10.6274 7.99611 10.6274Z" fill="black" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_228_36">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
</button>
<button id="system-theme-btn" class="theme-btn" onclick="setTheme('system')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_228_46)">
<path d="M1.54362 13.2758H14.4497C15.4161 13.2758 16 12.6082 16 11.5031V2.30216C16 1.19712 15.4161 0.53717 14.4497 0.53717H1.54362C0.583892 0.53717 0 1.19712 0 2.30216V11.5031C0 12.6082 0.583892 13.2758 1.54362 13.2758ZM1.56376 12.0403C1.26846 12.0403 1.08054 11.8254 1.08054 11.4878V2.32518C1.08054 1.97986 1.26846 1.77266 1.56376 1.77266H14.4362C14.7316 1.77266 14.9195 1.97986 14.9195 2.32518V11.4878C14.9195 11.8254 14.7316 12.0403 14.4362 12.0403H1.56376ZM5.87919 15.1022H10.1208V13.176H5.87919V15.1022ZM5.83892 16H10.1611C10.4564 16 10.698 15.7237 10.698 15.3784C10.698 15.0331 10.4564 14.7568 10.1611 14.7568H5.83892C5.54362 14.7568 5.29531 15.0331 5.29531 15.3784C5.29531 15.7237 5.54362 16 5.83892 16Z" fill="black" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_228_46">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
</button>
</div>
</div>
<div class="line"></div>
<a href="/" target="_blank">Главная страница
<svg data-testid="geist-icon" fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24" style="width: 20px; height: 20px;"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></svg>
</a>
<a href="/logout">Выйти из аккаунта</a>
<div class="line"></div>
<button onclick="location.href='/'" class="button">Связаться с нами</button>
</div>
</div>
</div>
</nav>
</header>
<nav class="sections">
<a href="/project/{{Name}}">Обзор</a>
<a href="/project/{{Name}}/progress">Прогресс</a>
<a href="/project/{{Name}}/documents">Документы</a>
<a href="/project/{{Name}}/payments">Оплата</a>
<a href="/project/{{Name}}/tests">Тесты</a>
{{#if IsAdmin}}
<a class="selected" href="/project/{{Name}}/settings">Настройки</a>
{{/if}}
</nav>
<div class="notifications"></div>
<section class="content-bg">
<div class="progress-name-section">
<h1>Настройки платежа с ID {{Payment.id}}</h1>
</div>
<div class="settings-content">
<nav class="settings-sections">
<a href="/project/{{Name}}/settings">Основные</a>
<a href="/project/{{Name}}/settings/modules">Модули</a>
<a class="selected" href="/project/{{Name}}/settings/payments">Платежи</a>
</nav>
<div class="setting-section">
<form id="edit-form" style="width: 100%;">
<div class="setting-top">
<h1>Данные платежа</h1>
<label for="name-input">Назначение</label>
<textarea style="max-width: 300px; box-sizing:border-box; border-radius:5px; padding: 10px;" name="name" type="text" id="name-input" autocorrect="off" autocapitalize="off" spellcheck="false" class="force-ltr form-textbox-input autoExpand" autocomplete="off" aria-invalid="false" required>{{Payment.name}}</textarea>
<label for="amount-input">Сумма</label>
<input name="amount" id="amount-input" type="number" value="{{Payment.amount}}" required>
<label for="paid-input">Оплачен ли</label>
<select name="paid" id="paid-input">
<option value="true">Да</option>
<option value="false">Нет</option>
</select>
</div>
<div class="setting-bottom">
<h2>Не забудьте проверить список доступных проектов.</h2>
<div class="buttons">
<button id="deletePayment" class="delete" type="button">Удалить</button>
<button id="editPayment" class="updateButton" type="submit">Сохранить</button>
</div>
</div>
</form>
</div>
<div class="setting-section">
<div class="setting-top">
<h1>Платежный документ</h1>
{{#if Payment.filepath}}
<a href="{{API_SERVER}}/{{Payment.filepath}}" target="_blank">Нажмите, чтобы посмотреть существующий файл</a>
{{/if}}
<div class="drop-zone">
<span class="drop-zone__prompt">Перетащите файл сюда или нажмите чтобы загрузить</span>
<input onchange="handleFileChange(this)" id="upload-file" type="file" name="file" class="drop-zone__input">
</div>
</div>
<div class="setting-bottom">
<h2>Можете загрузить новый файл или оставить существующий.</h2>
<div class="buttons">
{{#if Payment.filepath}}
<button id="deleteFile" class="delete" type="button" onclick="deleteFile();">Удалить существующий файл</button>
{{/if}}
<button id="updateFile" class="inactive updateButton" type="button" onclick="updateFile();">Обновить</button>
</div>
</div>
</div>
</div>
</section>
<div id="deletepayment-form-popup-bg" class="form-popup-bg not-main" >
<div class="form-container">
<img src="../../../../img/xmark.svg" id="btnCloseForm" class="close-button">
<h1>Вы уверены что хотите удалить этот платёж?</h1>
<button type="button" class="form-button" onclick="confirmDelete({{Payment.id}});" id="deleteConfirm">Удалить платёж</button>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("project-{{Project.id}}").classList.add("selected");
document.getElementById("paid-input").value = "{{Payment.paid}}";
});
</script>
<script src="../../../../scripts/notifications.js"></script>
<script>
function handleInputChange(input) {
const settingBottom = input.parentElement.nextElementSibling;
const button = settingBottom.querySelector('.updateButton');
button.classList.remove('inactive');
}
function getCookie(name) {
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.startsWith(name + "=")) {
return cookie.substring(name.length + 1);
}
}
return null;
}
</script>
<script>
function toggleProjects() {
if ($('#dropdownProjects').hasClass('is-visible')) {
event.preventDefault();
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
} else {
event.preventDefault();
$("#dropdownProjects").css("display", "inline-flex");
$('#dropdownProjects').addClass('is-visible');
}
}
$(document).on('click', function(event) {
if ($(event.target).closest('#headerProjects').length) {
return;
} else {
if (!$(event.target).closest('.dropdown-projects').length) {
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
}
}
});
$(document).ready(function() {
$(document).keydown(function(e) {
if (e.key === "Escape" || e.key === "Esc") {
console.log("Escape")
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
}
});
});
function closeForm() {
$('.form-popup-bg').removeClass('is-visible');
}
$(document).ready(function($) {
$('#deletePayment').on('click', function(event) {
event.preventDefault();
$('#deletepayment-form-popup-bg').addClass('is-visible');
});
$('#deletepayment-form-popup-bg').on('click', function(event) {
if ($(event.target).is('#deletepayment-form-popup-bg') || $(event.target).is('#btnCloseForm')) {
event.preventDefault();
$(this).removeClass('is-visible');
}
});
const form = document.getElementById("edit-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
$("#editPayment").addClass("inactive");
$("#editPayment").blur();
const formData = new FormData(form);
formData.append("id", '{{Payment.id}}')
fetch(API_SERVER + "/payment", {
method: "PUT",
headers: {
Authorization: getCookie("token"),
},
body: formData,
})
.then((response) => response.json())
.then((data) => {
notis.create(
"Изменения сохранены",
"Данные платежа успешно обновлены",
5
);
$("#editPayment").removeClass("inactive");
})
.catch((error) => {
notis.create(
"Ошибка",
"При сохранении данных платежа произошла ошибка",
5
);
$("#editUser").removeClass("inactive");
console.error("Ошибка:", error);
});
});
});
document.querySelectorAll(".drop-zone__input").forEach((inputElement) => {
const dropZoneElement = inputElement.closest(".drop-zone");
dropZoneElement.addEventListener("click", (e) => {
inputElement.click();
});
inputElement.addEventListener("change", (e) => {
if (inputElement.files.length) {
updateThumbnail(dropZoneElement, inputElement.files[0]);
}
});
dropZoneElement.addEventListener("dragover", (e) => {
e.preventDefault();
dropZoneElement.classList.add("drop-zone--over");
});
["dragleave", "dragend"].forEach((type) => {
dropZoneElement.addEventListener(type, (e) => {
dropZoneElement.classList.remove("drop-zone--over");
});
});
dropZoneElement.addEventListener("drop", (e) => {
e.preventDefault();
if (e.dataTransfer.files.length) {
inputElement.files = e.dataTransfer.files;
updateThumbnail(dropZoneElement, e.dataTransfer.files[0]);
const changeEvent = new Event("change");
inputElement.dispatchEvent(changeEvent);
}
dropZoneElement.classList.remove("drop-zone--over");
});
});
function updateThumbnail(dropZoneElement, file) {
let thumbnailElement = dropZoneElement.querySelector(".drop-zone__thumb");
if (dropZoneElement.querySelector(".drop-zone__prompt")) {
dropZoneElement.querySelector(".drop-zone__prompt").remove();
}
if (!thumbnailElement) {
thumbnailElement = document.createElement("div");
thumbnailElement.classList.add("drop-zone__thumb");
dropZoneElement.appendChild(thumbnailElement);
}
thumbnailElement.dataset.label = file.name;
if (file.type.startsWith("image/")) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
thumbnailElement.style.backgroundImage = `url('${reader.result}')`;
};
} else {
thumbnailElement.style.backgroundImage = null;
}
}
function handleFileChange(input) {
const settingBottom = input.parentElement.parentElement.nextElementSibling;
const button = settingBottom.querySelector('.updateButton');
button.classList.remove('inactive');
}
function confirmDelete(id) {
$.ajax({
url: API_SERVER + "/payment?id=" + id,
method: "DELETE",
headers: {
Authorization: getCookie("token"),
},
success: function(response) {
location.reload();
},
error: function() {
// Обработка ошибки при запросе к серверу
alert("Произошла ошибка при запросе к серверу.");
}
});
}
async function deleteFile() {
$("#deleteFile").addClass("inactive");
$("#deleteFile").blur();
const response = await fetch("{{API_SERVER}}/filepayment?id=" + {{Payment.id}}, {
method: "DELETE",
headers: {
Authorization: getCookie("token"),
"Content-Type": "application/json"
}
});
if (response.status === 200) {
$("#deleteFile").removeClass("inactive");
location.reload();
} else {
alert("Ошибка при обновлении данных.");
}
}
async function updateFile() {
$("#updateFile").addClass("inactive");
$("#updateFile").blur();
const name = '{{Project.name}}';
const uploadFileInput = $("#upload-file")[0];
if (!uploadFileInput.files.length) {
alert("Выберите файл для загрузки.");
return;
}
const formData = new FormData();
const uploadFile = $("#upload-file")[0].files[0];
formData.append("files", uploadFile);
formData.append("id", {{Payment.id}});
const response = await fetch("{{API_SERVER}}/payment", {
method: "PUT",
headers: {
Authorization: getCookie("token"),
},
body: formData,
});
if (response.status === 201) {
location.reload();
} else {
alert("Ошибка при загрузке файла.");
}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,453 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Настройка платежей</title>
<link rel="icon" type="image/x-icon" href="../../../img/favicon.png">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<link rel="stylesheet" href="../../../styles/main.css">
<script src="../../../scripts/jquery.min.js"></script>
<script>
const API_SERVER = "{{API_SERVER}}";
let payments = [
{{#each Payments}}
{
id: {{this.id}},
name: "{{this.name}}",
amount: {{this.amount}},
paid: {{this.paid}},
lastupdate: "{{this.lastupdate}}",
},
{{/each}}
];
</script>
<script type="module">
import { minidenticonSvg } from 'https://cdn.jsdelivr.net/npm/minidenticons@4.2.0/minidenticons.min.js'
</script>
<script src="../../../scripts/projects.js"></script>
<script src="../../../scripts/full-payments-table.js"></script>
</head>
<body>
<header class="lk-header">
<div class="header-logo">
<a href="/projects"><img src="../../../img/krbl.svg">{{#if Project.maraku}} X <img onclick="window.open('https://maraku.ru/', '_blank')" src="../../../img/maraku.svg">{{/if}}</a>
<span class="slash">/</span>
<span>{{Project.displayname}}</span>
<div class="dropdown">
<button id="headerProjects" type="button" onclick="toggleProjects();">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="18" viewBox="0 0 13 18" fill="none">
<path d="M6.93296 0.392929C6.70015 0.392929 6.49422 0.48226 6.31514 0.660923L1.20253 5.55627C1.06822 5.69026 0.969727 5.87786 0.969727 6.13691C0.969727 6.60146 1.31892 6.95876 1.78452 6.95876C1.9815 6.95876 2.1964 6.9052 2.38442 6.7176L6.93296 2.27782L11.4725 6.7176C11.6695 6.89623 11.8754 6.95876 12.0724 6.95876C12.538 6.95876 12.8872 6.60146 12.8872 6.13691C12.8872 5.87786 12.7977 5.69026 12.6544 5.55627L7.5418 0.660923C7.36271 0.48226 7.15679 0.392929 6.93296 0.392929ZM6.93296 17.5981C7.15679 17.5981 7.36271 17.4999 7.5418 17.3302L12.6544 12.4348C12.7977 12.2918 12.8872 12.1132 12.8872 11.8452C12.8872 11.3807 12.538 11.0323 12.0724 11.0323C11.8754 11.0323 11.6695 11.0948 11.4725 11.2735L6.93296 15.7132L2.38442 11.2735C2.1964 11.0859 1.9815 11.0323 1.78452 11.0323C1.31892 11.0323 0.969727 11.3807 0.969727 11.8452C0.969727 12.1132 1.06822 12.2918 1.20253 12.4348L6.31514 17.3302C6.49422 17.4999 6.70015 17.5981 6.93296 17.5981Z" fill="black" fill-opacity="0.6"/>
</svg>
</button>
<div id="dropdownProjects" class="dropdown-projects">
<input type="text" placeholder="Найти проект...">
<h1>Проекты</h1>
{{#each Projects}}
<div onclick="location.href='/project/{{this.name}}'" id="project-{{this.id}}" class="project"> {{#if this.avatar}} <div class="avatar-container"><img src="{{../API_SERVER}}/{{this.avatar}}"></div>{{/if}} {{this.displayname}}
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 20 20">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".6" d="M7.388 20c.487 0 .873-.215 1.145-.635L19.24 2.505c.204-.33.283-.579.283-.84 0-.623-.408-1.03-1.031-1.03-.453 0-.703.147-.975.577L7.343 17.428l-5.28-6.912c-.284-.397-.567-.556-.975-.556C.442 9.96 0 10.402 0 11.025c0 .261.113.556.329.828l5.88 7.49c.34.442.692.657 1.18.657Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h19.524v20H0z"/>
</clipPath>
</defs>
</svg>
</div>
{{/each}}
</div>
</div>
</div>
<nav>
<a onclick="alert('Этот раздел в разработке.');">Новости</a>
<a onclick="alert('Этот раздел в разработке.');">Помощь</a>
<div class="user">
<svg class="user-svg ring" width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 16.8241C0 17.5978 0.593536 18.1066 1.60042 18.1066H6.07316C6.15794 20.1522 7.75836 21.9434 9.99473 21.9434C12.2416 21.9434 13.8421 20.1627 13.9269 18.1066H18.3996C19.3959 18.1066 20 17.5978 20 16.8241C20 15.7642 18.9189 14.8103 18.0074 13.867C17.3079 13.1357 17.1171 11.6307 17.0323 10.4118C16.9581 6.23586 15.8771 3.54376 13.0578 2.52627C12.6974 1.13782 11.5633 0.0461426 9.99473 0.0461426C8.43668 0.0461426 7.29201 1.13782 6.94224 2.52627C4.12295 3.54376 3.04187 6.23586 2.96768 10.4118C2.88288 11.6307 2.69211 13.1357 1.99258 13.867C1.07048 14.8103 0 15.7642 0 16.8241ZM2.05618 16.5061V16.379C2.24695 16.0716 2.88288 15.4462 3.43403 14.8315C4.19714 13.9836 4.55748 12.6164 4.6529 10.5496C4.73769 5.9179 6.11553 4.44465 7.92793 3.94652C8.19292 3.88292 8.3413 3.75574 8.3519 3.48017C8.38367 2.37789 9.01963 1.60417 9.99473 1.60417C10.9804 1.60417 11.6057 2.37789 11.6481 3.48017C11.6587 3.75574 11.7965 3.88292 12.0615 3.94652C13.8845 4.44465 15.2623 5.9179 15.3471 10.5496C15.4425 12.6164 15.8029 13.9836 16.5554 14.8315C17.1171 15.4462 17.7424 16.0716 17.9332 16.379V16.5061H2.05618ZM7.72658 18.1066H12.2735C12.1887 19.548 11.2772 20.4489 9.99473 20.4489C8.72286 20.4489 7.80077 19.548 7.72658 18.1066Z" fill="black" fill-opacity="0.85"/>
</svg>
<div class="dropdown">
<minidenticon-svg onclick="toggleAccount();" id="userIcon" style="height: 40px;" username="{{User.email}}"></minidenticon-svg>
<div id="dropdownAccount" class="dropdown-account">
<div class="user-name">
<h1>{{User.name}}</h1>
<h2>{{User.email}}</h2>
</div>
<a href="/user/settings">Настройки профиля <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 18 18">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".85" d="M8.15 17.992h1.7c.647 0 1.143-.396 1.295-1.019l.362-1.573.269-.093 1.37.842c.547.345 1.178.26 1.64-.202l1.178-1.17c.463-.463.547-1.102.202-1.64l-.858-1.364.101-.253 1.573-.37A1.301 1.301 0 0 0 18 9.854V8.188c0-.64-.395-1.145-1.018-1.296l-1.556-.379-.11-.269.859-1.363c.345-.539.26-1.17-.202-1.641l-1.178-1.178c-.454-.455-1.085-.539-1.631-.202l-1.371.841-.286-.11-.362-1.573C10.993.396 10.497 0 9.85 0h-1.7c-.647 0-1.143.396-1.295 1.018l-.37 1.574-.286.11-1.363-.842c-.546-.337-1.186-.253-1.64.202L2.027 3.24c-.463.471-.555 1.102-.202 1.64l.85 1.364-.101.27-1.556.378A1.293 1.293 0 0 0 0 8.188v1.666a1.3 1.3 0 0 0 1.018 1.296l1.573.37.092.253-.85 1.363c-.353.539-.26 1.178.203 1.641l1.169 1.17c.462.463 1.102.547 1.648.202l1.363-.842.269.093.37 1.573c.152.623.648 1.019 1.295 1.019Zm.135-1.313c-.143 0-.219-.06-.244-.194l-.505-2.087a4.748 4.748 0 0 1-1.354-.555L4.35 14.97c-.101.076-.21.06-.312-.042l-.992-.993c-.093-.092-.101-.193-.034-.31l1.127-1.819a6.132 6.132 0 0 1-.546-1.346l-2.086-.496c-.135-.026-.194-.101-.194-.245V8.314c0-.151.05-.219.194-.244l2.077-.505c.135-.547.387-1.043.538-1.355L3.003 4.393c-.076-.127-.067-.227.025-.328l1.001-.977c.1-.1.193-.117.32-.042L6.165 4.15a6.821 6.821 0 0 1 1.38-.556l.496-2.087c.025-.134.101-.193.244-.193h1.43c.143 0 .219.059.235.193l.514 2.104c.521.135.975.345 1.354.547l1.825-1.11c.135-.076.219-.06.328.041l.992.977c.102.1.102.201.026.328L13.87 6.21c.16.312.404.808.538 1.355l2.086.505c.135.025.194.093.194.244V9.72c0 .144-.067.22-.194.245l-2.094.496a5.75 5.75 0 0 1-.547 1.346l1.127 1.818c.068.118.068.219-.033.311l-.984.993c-.11.101-.21.118-.32.042l-1.834-1.127a4.69 4.69 0 0 1-1.345.555l-.514 2.087c-.016.135-.092.194-.235.194h-1.43ZM9 12.21c1.758 0 3.205-1.447 3.205-3.214 0-1.75-1.447-3.198-3.205-3.198S5.787 7.245 5.787 8.996A3.23 3.23 0 0 0 9 12.21Zm0-1.304a1.91 1.91 0 0 1-1.9-1.91c0-1.035.857-1.894 1.9-1.894 1.026 0 1.884.859 1.884 1.894 0 1.043-.858 1.91-1.884 1.91Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h18v18H0z"/>
</clipPath>
</defs>
</svg>
</a>
<a href="/projects">Смотреть проекты
<svg xmlns="http://www.w3.org/2000/svg" style="width: 16px !important; height: 16px !important;" width="16" height="16" fill="none" viewBox="0 0 16 16">
<g clip-path="url(#a)">
<path fill="#000" fill-opacity=".85" d="M1.973 11.72a.917.917 0 0 0-.911-.925c-.494 0-.895.42-.895.925a.901.901 0 1 0 1.805 0Zm0 3.355c0-.505-.401-.933-.911-.933-.494 0-.895.428-.895.933 0 .514.401.925.895.925.51 0 .91-.41.91-.925Zm13.726-3.355c0-.377-.3-.66-.71-.66H3.736c-.41 0-.71.283-.71.66 0 .376.3.667.71.667h11.252c.41 0 .71-.29.71-.667Zm0 3.355c0-.376-.3-.659-.71-.659H3.736c-.41 0-.71.283-.71.66 0 .376.3.667.71.667h11.252c.41 0 .71-.29.71-.668ZM2.316.205C.61.205 0 .967 0 2.628v3.98C0 8.27.61 9.033 2.316 9.033h11.368C15.39 9.032 16 8.27 16 6.609v-3.98C16 .966 15.39.204 13.684.204H2.316Zm-.97 6.447V2.585c0-.762.242-1.095.978-1.095h11.352c.736 0 .978.333.978 1.095v4.067c0 .762-.242 1.095-.978 1.095H2.324c-.736 0-.978-.333-.978-1.095Z"/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h16v16H0z"/>
</clipPath>
</defs>
</svg>
</a>
<div class="line"></div>
<div class="theme-selector">
<span>Тема</span>
<div class="theme-switcher">
<button id="light-theme-btn" class="theme-btn" onclick="setTheme('light')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M12.493 10.7193C8.11132 10.7193 5.39164 8.09866 5.39164 3.89146C5.39164 2.69166 5.59046 1.63394 5.88469 1.06561C6.00397 0.836704 6.02785 0.726195 6.02785 0.568327C6.02785 0.307844 5.7813 0 5.4473 0C5.38369 0 5.23262 0.0236803 5.00995 0.110508C2.0676 1.29453 0 4.37297 0 7.68821C0 12.4795 3.50696 15.9684 8.33398 15.9684C11.7933 15.9684 14.6004 14.1687 15.8887 11.2166C15.9841 11.0113 16 10.8377 16 10.7509C16 10.4272 15.7217 10.2062 15.4752 10.2062C15.3479 10.2062 15.2525 10.2141 15.0616 10.2851C14.4175 10.5456 13.4473 10.7193 12.493 10.7193ZM1.24851 7.63296C1.24851 5.17809 2.53678 2.84164 4.59641 1.55501C4.34196 2.2891 4.20675 3.10212 4.20675 4.00196C4.20675 8.93537 7.23658 11.8717 12.3101 11.8717C13.1292 11.8717 13.8211 11.777 14.4811 11.5481C13.2724 13.5294 10.9424 14.7371 8.3817 14.7371C4.25447 14.7371 1.24851 11.7533 1.24851 7.63296Z" fill="black" fill-opacity="0.85"/>
</svg>
</button>
<button id="dark-theme-btn" class="theme-btn" onclick="setTheme('dark')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_228_36)">
<path d="M8.0037 2.86688C8.35137 2.86688 8.63985 2.57946 8.63985 2.2257V0.641179C8.63985 0.287425 8.35137 0 8.0037 0C7.64863 0 7.36015 0.287425 7.36015 0.641179V2.2257C7.36015 2.57946 7.64863 2.86688 8.0037 2.86688ZM11.6283 4.37772C11.8798 4.62091 12.2867 4.62828 12.5381 4.37772L13.6699 3.25012C13.914 3.00691 13.914 2.5942 13.6699 2.34362C13.4258 2.10042 13.019 2.10042 12.7675 2.34362L11.6283 3.47857C11.3842 3.72915 11.3842 4.13451 11.6283 4.37772ZM13.1299 7.99633C13.1299 8.3427 13.4258 8.63014 13.7735 8.63014H15.3638C15.7115 8.63014 16 8.3427 16 7.99633C16 7.64994 15.7115 7.35513 15.3638 7.35513H13.7735C13.4258 7.35513 13.1299 7.64994 13.1299 7.99633ZM11.6283 11.6149C11.3842 11.8655 11.3842 12.2708 11.6283 12.5141L12.7675 13.6564C13.019 13.8922 13.4258 13.8849 13.6699 13.649C13.914 13.3985 13.914 12.9931 13.6699 12.7499L12.5307 11.6149C12.2867 11.3791 11.8798 11.3791 11.6283 11.6149ZM8.0037 13.1257C7.64863 13.1257 7.36015 13.4132 7.36015 13.7596V15.3515C7.36015 15.6979 7.64863 15.9853 8.0037 15.9853C8.35137 15.9853 8.63985 15.6979 8.63985 15.3515V13.7596C8.63985 13.4132 8.35137 13.1257 8.0037 13.1257ZM4.3717 11.6149C4.12019 11.3791 3.70595 11.3791 3.46187 11.6149L2.3301 12.7425C2.08599 12.9857 2.08599 13.3911 2.3227 13.6416C2.56681 13.8775 2.98105 13.8849 3.23253 13.649L4.36431 12.5141C4.60843 12.2708 4.60843 11.8655 4.3717 11.6149ZM2.87009 7.99633C2.87009 7.64994 2.5742 7.35513 2.22654 7.35513H0.636154C0.288488 7.35513 0 7.64994 0 7.99633C0 8.3427 0.288488 8.63014 0.636154 8.63014H2.22654C2.5742 8.63014 2.87009 8.3427 2.87009 7.99633ZM4.36431 4.37772C4.60843 4.14187 4.60843 3.72179 4.3717 3.47857L3.23996 2.34362C2.99584 2.10779 2.5816 2.10042 2.33749 2.34362C2.09339 2.5942 2.09339 3.00691 2.3301 3.24275L3.46187 4.37772C3.70595 4.62091 4.1128 4.62091 4.36431 4.37772Z" fill="black" fill-opacity="0.85"/>
<path d="M7.99611 11.755C10.0525 11.755 11.7613 10.0525 11.7613 7.99636C11.7613 5.93277 10.0525 4.23035 7.99611 4.23035C5.93971 4.23035 4.23096 5.93277 4.23096 7.99636C4.23096 10.0525 5.93971 11.755 7.99611 11.755ZM7.99611 10.6274C6.55368 10.6274 5.35534 9.43347 5.35534 7.99636C5.35534 6.55185 6.55368 5.35792 7.99611 5.35792C9.43854 5.35792 10.6369 6.55185 10.6369 7.99636C10.6369 9.43347 9.43854 10.6274 7.99611 10.6274Z" fill="black" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_228_36">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
</button>
<button id="system-theme-btn" class="theme-btn" onclick="setTheme('system')">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<g clip-path="url(#clip0_228_46)">
<path d="M1.54362 13.2758H14.4497C15.4161 13.2758 16 12.6082 16 11.5031V2.30216C16 1.19712 15.4161 0.53717 14.4497 0.53717H1.54362C0.583892 0.53717 0 1.19712 0 2.30216V11.5031C0 12.6082 0.583892 13.2758 1.54362 13.2758ZM1.56376 12.0403C1.26846 12.0403 1.08054 11.8254 1.08054 11.4878V2.32518C1.08054 1.97986 1.26846 1.77266 1.56376 1.77266H14.4362C14.7316 1.77266 14.9195 1.97986 14.9195 2.32518V11.4878C14.9195 11.8254 14.7316 12.0403 14.4362 12.0403H1.56376ZM5.87919 15.1022H10.1208V13.176H5.87919V15.1022ZM5.83892 16H10.1611C10.4564 16 10.698 15.7237 10.698 15.3784C10.698 15.0331 10.4564 14.7568 10.1611 14.7568H5.83892C5.54362 14.7568 5.29531 15.0331 5.29531 15.3784C5.29531 15.7237 5.54362 16 5.83892 16Z" fill="black" fill-opacity="0.85"/>
</g>
<defs>
<clipPath id="clip0_228_46">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>
</button>
</div>
</div>
<div class="line"></div>
<a href="/" target="_blank">Главная страница
<svg data-testid="geist-icon" fill="none" height="24" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24" style="width: 20px; height: 20px;"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></svg>
</a>
<a href="/logout">Выйти из аккаунта</a>
<div class="line"></div>
<button onclick="location.href='/'" class="button">Связаться с нами</button>
</div>
</div>
</div>
</nav>
</header>
<nav class="sections">
<a href="/project/{{Name}}">Обзор</a>
<a href="/project/{{Name}}/progress">Прогресс</a>
<a href="/project/{{Name}}/documents">Документы</a>
<a href="/project/{{Name}}/payments">Оплата</a>
<a href="/project/{{Name}}/tests">Тесты</a>
{{#if IsAdmin}}
<a class="selected" href="/project/{{Name}}/settings">Настройки</a>
{{/if}}
</nav>
<div class="notifications"></div>
<section class="content-bg">
<div class="progress-name-section">
<h1>Настройки проекта</h1>
<h2>Здесь можно изменить основную информацию и обновить фотокарточки проекта.</h2>
</div>
<div class="settings-content">
<nav class="settings-sections">
<a href="/project/{{Name}}/settings">Основные</a>
<a href="/project/{{Name}}/settings/modules">Модули</a>
<a class="selected" href="/project/{{Name}}/settings/payments">Платежи</a>
</nav>
<div class="table-search-section" style="width: 100%;">
<input type="text" class="updates-search search-input" placeholder="Поиск платежей...">
<button id="addPayment" class="upload-button"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20">
<path fill="#fff" fill-opacity=".85" d="M0 9.994c0 .594.497 1.078 1.079 1.078H8.92v7.838a1.09 1.09 0 0 0 1.079 1.078 1.1 1.1 0 0 0 1.09-1.078v-7.838h7.831c.582 0 1.079-.484 1.079-1.078a1.1 1.1 0 0 0-1.079-1.09h-7.83V1.078A1.1 1.1 0 0 0 10 0a1.09 1.09 0 0 0-1.079 1.078v7.826H1.08A1.1 1.1 0 0 0 0 9.994Z"/>
</svg>
Добавить платёж</button>
</div>
<table class="users-table" id="paymentsTable">
<thead>
<tr>
<th>Назначение</th>
<th>Сумма</th>
<th>Оплачен ли</th>
<th>Последнее обновление</th>
</tr>
</thead>
<tbody>
<!-- Сюда будут добавляться строки таблицы -->
</tbody>
</table>
</div>
</section>
<form id="paymentForm">
<div id="addpayment-form-popup-bg" class="form-popup-bg not-main" >
<div class="form-container">
<img src="../../../img/xmark.svg" id="btnCloseForm" class="close-button">
<h1>Добавление нового платежа</h1>
<div class="form-cell-wrapper form-textbox">
<input type="text" id="addpayment-name" autocorrect="off" autocapitalize="off" aria-required="true" required="required" spellcheck="false" class="force-ltr form-textbox-input" autocomplete="off" aria-invalid="false" onfocus="focusHandler(this)" onblur="blurHandler(this)">
<span aria-hidden="true" id="addpayment-name-label" class="form-textbox-label form-label-flyout">Назначение платежа</span>
</div>
<div class="form-cell-wrapper form-textbox">
<input type="text" id="addpayment-amount" autocorrect="off" autocapitalize="off" aria-required="true" required="required" spellcheck="false" class="force-ltr form-textbox-input" autocomplete="off" aria-invalid="false" onfocus="focusHandler(this)" onblur="blurHandler(this)">
<span aria-hidden="true" id="addpayment-amount-label" class="form-textbox-label form-label-flyout">Сумма</span>
</div>
<br>
<div class="form-cell-wrapper form-textbox">
<label style="position: absolute; top: -25px;" for="addpayment-paid">Оплачен ли</label>
<select type="text" id="addpayment-paid" autocorrect="off" autocapitalize="off" aria-required="true" required="required" spellcheck="false" autocomplete="off" aria-invalid="false">
<option value="false">Нет</option>
<option value="true">Да</option>
</select>
</div>
<div class="drop-zone">
<span class="drop-zone__prompt">Перетащите файл сюда или нажмите чтобы загрузить</span>
<input id="upload-file" type="file" name="file" class="drop-zone__input">
</div>
<button type="submit" class="form-button" id="addPaymentSubmit">Добавить платеж</button>
</div>
</div>
</form>
<script>
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("project-{{Project.id}}").classList.add("selected");
});
</script>
<script>
function handleInputChange(input) {
const settingBottom = input.parentElement.nextElementSibling;
const button = settingBottom.querySelector('.updateButton');
button.classList.remove('inactive');
}
function getCookie(name) {
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.startsWith(name + "=")) {
return cookie.substring(name.length + 1);
}
}
return null;
}
</script>
<script>
function toggleProjects() {
if ($('#dropdownProjects').hasClass('is-visible')) {
event.preventDefault();
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
} else {
event.preventDefault();
$("#dropdownProjects").css("display", "inline-flex");
$('#dropdownProjects').addClass('is-visible');
}
}
$(document).on('click', function(event) {
if ($(event.target).closest('#headerProjects').length) {
return;
} else {
if (!$(event.target).closest('.dropdown-projects').length) {
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
}
}
});
$(document).ready(function() {
$(document).keydown(function(e) {
if (e.key === "Escape" || e.key === "Esc") {
console.log("Escape")
$('#dropdownProjects').removeClass('is-visible');
setTimeout(function() {
$("#dropdownProjects").css("display", "none");
}, 200);
}
});
});
function closeForm() {
$('.form-popup-bg').removeClass('is-visible');
}
$(document).ready(function($) {
$('#addPayment').on('click', function(event) {
event.preventDefault();
$('#addpayment-form-popup-bg').addClass('is-visible');
});
$('#addpayment-form-popup-bg').on('click', function(event) {
if ($(event.target).is('#addpayment-form-popup-bg') || $(event.target).is('#btnCloseForm')) {
event.preventDefault();
$(this).removeClass('is-visible');
}
});
});
document.querySelectorAll(".drop-zone__input").forEach((inputElement) => {
const dropZoneElement = inputElement.closest(".drop-zone");
dropZoneElement.addEventListener("click", (e) => {
inputElement.click();
});
inputElement.addEventListener("change", (e) => {
if (inputElement.files.length) {
updateThumbnail(dropZoneElement, inputElement.files[0]);
}
});
dropZoneElement.addEventListener("dragover", (e) => {
e.preventDefault();
dropZoneElement.classList.add("drop-zone--over");
});
["dragleave", "dragend"].forEach((type) => {
dropZoneElement.addEventListener(type, (e) => {
dropZoneElement.classList.remove("drop-zone--over");
});
});
dropZoneElement.addEventListener("drop", (e) => {
e.preventDefault();
if (e.dataTransfer.files.length) {
inputElement.files = e.dataTransfer.files;
updateThumbnail(dropZoneElement, e.dataTransfer.files[0]);
const changeEvent = new Event("change");
inputElement.dispatchEvent(changeEvent);
}
dropZoneElement.classList.remove("drop-zone--over");
});
});
function updateThumbnail(dropZoneElement, file) {
let thumbnailElement = dropZoneElement.querySelector(".drop-zone__thumb");
if (dropZoneElement.querySelector(".drop-zone__prompt")) {
dropZoneElement.querySelector(".drop-zone__prompt").remove();
}
if (!thumbnailElement) {
thumbnailElement = document.createElement("div");
thumbnailElement.classList.add("drop-zone__thumb");
dropZoneElement.appendChild(thumbnailElement);
}
thumbnailElement.dataset.label = file.name;
if (file.type.startsWith("image/")) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
thumbnailElement.style.backgroundImage = `url('${reader.result}')`;
};
} else {
thumbnailElement.style.backgroundImage = null;
}
}
document.addEventListener("DOMContentLoaded", function() {
const paymentForm = document.getElementById("paymentForm");
const nameInput = document.getElementById("addpayment-name");
const amountInput = document.getElementById("addpayment-amount");
const paidInput = document.getElementById("addpayment-paid");
const fileInput = document.getElementById("upload-file");
paymentForm.addEventListener("submit", async function(event) {
event.preventDefault();
const formData = new FormData();
formData.append("project", "{{Project.name}}");
formData.append("name", nameInput.value);
formData.append("amount", amountInput.value);
formData.append("paid", paidInput.value);
formData.append("files", fileInput.files[0]);
// Отправляем запрос на сервер для авторизации
const response = await fetch("{{API_SERVER}}/payment", {
method: "POST",
headers: {
"Authorization": getCookie("token"),
},
body: formData,
});
if (response.status === 201) {
const data = await response.json();
location.reload();
} else {
alert("Ошибка загрузки");
}
});
});
</script>
</body>
</html>

View File

@@ -165,7 +165,13 @@
<h2>Здесь можно изменить основную информацию и обновить фотокарточки проекта.</h2>
</div>
<div class="account-content">
<div class="settings-content">
<nav class="settings-sections">
<a class="selected" href="/project/{{Name}}/settings">Основные</a>
<a href="/project/{{Name}}/settings/modules">Модули</a>
<a href="/project/{{Name}}/settings/payments">Платежи</a>
</nav>
<div class="setting-section">
<div class="setting-top">
@@ -340,27 +346,7 @@
}
});
});
function closeForm() {
$('.form-popup-bg').removeClass('is-visible');
}
$(document).ready(function($) {
$('#uploadDocument').on('click', function(event) {
event.preventDefault();
$('#feedback-form-popup-bg').addClass('is-visible');
});
$('#feedback-form-popup-bg').on('click', function(event) {
if ($(event.target).is('#feedback-form-popup-bg') || $(event.target).is('#btnCloseForm')) {
event.preventDefault();
$(this).removeClass('is-visible');
}
});
});
document.querySelectorAll(".drop-zone__input").forEach((inputElement) => {
const dropZoneElement = inputElement.closest(".drop-zone");