Большое обновление

This commit is contained in:
2025-01-02 14:42:15 +03:00
parent 4428052d78
commit 098eeb468e
14 changed files with 633 additions and 118 deletions

View File

@@ -1,22 +0,0 @@
@page "/counter"
@using Otchinslator.Components.Layout
@layout OtchislenieLayout
@rendermode InteractiveServer
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}

View File

@@ -2,19 +2,20 @@
@page "/otchislenie/questionnaire"
@using Otchinslator.Components.Layout
@layout OtchislenieLayout
@using BlazorPageScript
<PageScript Src="./Components/Pages/Questionnaire.razor.js" />
<style>
.knobs, .layer
{
.knobs, .layer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.button-custom
{
.button-custom {
position: relative;
top: 50%;
width: 5rem;
@@ -23,9 +24,8 @@
overflow: hidden;
margin-top: 4px;
}
.checkbox-custom
{
.checkbox-custom {
position: relative;
width: 100%;
height: 100%;
@@ -36,13 +36,11 @@
z-index: 3;
}
.knobs
{
.knobs {
z-index: 2;
}
#button-custom-1 .knobs:before
{
#button-custom-1 .knobs:before {
content: '';
position: absolute;
top: 4px;
@@ -53,13 +51,12 @@
text-align: center;
font-size: 22px;
padding: 1px 12px 12px 11px;
background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));
background-color: var(--fallback-p, oklch(var(--p)/var(--tw-bg-opacity)));
border-radius: 50%;
transition: 0.3s cubic-bezier(0.18, 0.89, 0.35, 1.15) all;
}
#button-custom-1 .checkbox-custom:checked + .knobs:before
{
#button-custom-1 .checkbox-custom:checked + .knobs:before {
content: '$';
left: 42px;
background-color: #89E592;
@@ -93,7 +90,10 @@
</dialog>
<div class="relative">
<div class="text-center font-bold text-4xl md:text-5xl w-max absolute left-1/2 -top-1/3 transform -translate-x-1/2 italic"><br>Небольшая анкета</div>
<div
class="text-center font-bold text-4xl md:text-5xl w-max absolute left-1/2 -top-1/3 transform -translate-x-1/2 italic">
<br>Небольшая анкета
</div>
<div class="flex flex-col space-y-4 w-96">
<div class="card rounded-badge bg-base-200 p-4">
<h2 class="card-title text-center text-3xl justify-center my-4">Кто ты воин?</h2>
@@ -135,53 +135,11 @@
</div>
<div class="join w-full mt-4 flex gap-2">
<button onclick="exit_modal.showModal()" class="relative btn btn-primary rounded-full flex-grow-0 w-[3rem] h-[3rem]">
<button onclick="exit_modal.showModal()"
class="relative btn btn-primary rounded-full flex-grow-0 w-[3rem] h-[3rem]">
<img class="absolute p-3" src="img/exit.svg" alt=""/>
</button>
<a href="otchislenie/statement" class="btn rounded-full btn-primary flex-grow w-30">Продолжим</a>
<button onclick="info_modal.showModal()" class="btn btn-primary rounded-full flex-grow-0 w-[3rem]">?</button>
</div>
</div>
@* TODO: Баг, если вернуться обратно через Nav то скрипты не грузятся *@
<script defer>
document.getElementById('phoneNumberInput').addEventListener('input', function (e) {
e.target.value = e.target.value.replace(/\D/g, '').slice(0, 10); // Limit to 10 digits
let num = e.target.value;
if (num.length > 3 && num.length <= 6) {
e.target.value = num.substring(0,3) + ' ' + num.substring(3,6);
} else if (num.length > 6 && num.length <= 8) {
e.target.value = num.substring(0,3) + ' ' + num.substring(3,6) + ' ' + num.substring(6,8);
} else if (num.length > 8) {
e.target.value = num.substring(0,3) + ' ' + num.substring(3,6) + ' ' + num.substring(6,10);
}
});
</script>
<script>
const continueButton = document.querySelector('a[href="otchislenie/statement"]');
const options = document.querySelectorAll('input[name="options"]');
const kurs = document.querySelectorAll('input[name="kurs"]');
const phoneNumberInput = document.getElementById('phoneNumberInput');
function validateForm() {
const isOptionSelected = Array.from(options).some(option => option.checked);
const isKursSelected = Array.from(kurs).some(k => k.checked);
const isPhoneNumberValid = phoneNumberInput.value.length === 12;
// log
console.log(isOptionSelected, isKursSelected, isPhoneNumberValid);
if (isOptionSelected && isKursSelected && isPhoneNumberValid) {
continueButton.classList.remove('btn-disabled');
} else {
continueButton.classList.add('btn-disabled');
}
}
options.forEach(option => option.addEventListener('change', validateForm));
kurs.forEach(k => k.addEventListener('change', validateForm));
phoneNumberInput.addEventListener('input', validateForm);
validateForm(); // Initial validation
</script>

View File

@@ -0,0 +1,106 @@
export function onLoad() {
// Подготовка поля ввода номера телефона
document.getElementById('phoneNumberInput').addEventListener('input', function (e) {
e.target.value = e.target.value.replace(/\D/g, '').slice(0, 10); // Limit to 10 digits
let num = e.target.value;
if (num.length > 3 && num.length <= 6) {
e.target.value = num.substring(0, 3) + ' ' + num.substring(3, 6);
} else if (num.length > 6 && num.length <= 8) {
e.target.value = num.substring(0, 3) + ' ' + num.substring(3, 6) + ' ' + num.substring(6, 8);
} else if (num.length > 8) {
e.target.value = num.substring(0, 3) + ' ' + num.substring(3, 6) + ' ' + num.substring(6, 10);
}
});
const continueButton = document.querySelector('a[href="otchislenie/statement"]');
const options = document.querySelectorAll('input[name="options"]');
const kursElements = document.querySelectorAll('input[name="kurs"]');
const phoneNumberInput = document.getElementById('phoneNumberInput');
const kursElement2 = Array.from(kursElements).find(k => k.getAttribute('aria-label') === '2');
const kursElement3 = Array.from(kursElements).find(k => k.getAttribute('aria-label') === '3');
const kursElement4 = Array.from(kursElements).find(k => k.getAttribute('aria-label') === '4');
const kursElement5 = Array.from(kursElements).find(k => k.getAttribute('aria-label') === '5');
// Загрузка данных из хранилища если данные есть
function loadFromLocalStorage() {
const phoneNumber = localStorage.getItem('phoneNumber');
const paid = localStorage.getItem('paid');
const option = localStorage.getItem('option');
const kurs = localStorage.getItem('kurs');
if (phoneNumber) {
phoneNumberInput.value = phoneNumber;
}
if (paid) {
document.querySelector('.checkbox-custom').checked = paid;
}
if (option) {
const optionElement = Array.from(options).find(optionElement => optionElement.getAttribute('aria-label') === option);
if (optionElement) {
optionElement.checked = true;
}
}
if (kurs) {
const kursElement = Array.from(kursElements).find(kursElement => kursElement.getAttribute('aria-label') === kurs);
if (kursElement) {
kursElement.checked = true;
}
}
}
function validateForm() {
const isOptionSelected = Array.from(options).some(option => option.checked);
const isKursSelected = Array.from(kursElements).some(k => k.checked);
const isPhoneNumberValid = phoneNumberInput.value.length === 12;
var tupeOfEducation = (Array.from(options).find(option => option.checked).getAttribute('aria-label'));
if (tupeOfEducation === "Баклан") {
kursElement3.disabled = false;
kursElement4.disabled = false;
kursElement5.disabled = true;
if (kursElement5.checked) {
kursElement5.checked = false;
kursElement4.checked = true;
}
} else if (tupeOfEducation === "Маг") {
kursElement3.disabled = true;
kursElement4.disabled = true;
kursElement5.disabled = true;
if (kursElement5.checked || kursElement4.checked || kursElement3.checked) {
kursElement5.checked = false;
kursElement4.checked = false;
kursElement3.checked = false;
kursElement2.checked = true;
}
} else if (tupeOfEducation === "Спец") {
kursElement3.disabled = false;
kursElement4.disabled = false;
kursElement5.disabled = false;
}
if (isOptionSelected && isKursSelected && isPhoneNumberValid) {
continueButton.classList.remove('btn-disabled');
localStorage.setItem('phoneNumber', phoneNumberInput.value);
localStorage.setItem('paid', document.querySelector('.checkbox-custom').checked);
localStorage.setItem('option', tupeOfEducation);
localStorage.setItem('kurs', Array.from(kursElements).find(k => k.checked).getAttribute('aria-label'));
} else {
continueButton.classList.add('btn-disabled');
}
}
options.forEach(option => option.addEventListener('change', validateForm));
kursElements.forEach(k => k.addEventListener('change', validateForm));
phoneNumberInput.addEventListener('input', validateForm);
loadFromLocalStorage();
validateForm();
}

View File

@@ -3,9 +3,10 @@
@layout OtchislenieLayout
<script>
function showCongratulation() {
document.getElementById('downloadPDF').addEventListener('click', function () {
document.getElementById('congratulation').classList.remove('hidden');
}
});
</script>
<dialog id="SendToDirectorModal" class="modal modal-bottom sm:modal-middle">
@@ -20,35 +21,63 @@
</div>
</div>
</dialog>
<div class="w-full">
<div class="flex flex-col space-y-4 xl:w-1/2 sm:w-full mx-auto">
<div class="card rounded-badge bg-base-200 p-4">
<div class="flex flex-col space-y-4 mt-1">
<button onclick="SendToDirectorModal.showModal()" class="btn h-16 btn-primary rounded-full text-2xl relative">
Отправить директору
</button>
<button id="downloadPDF" onclick="showCongratulation()" class="btn h-16 btn-primary rounded-full text-2xl relative">
Скачать PDF
<div class="absolute bg-base-200 rounded-full right-1 w-14 h-14">
<img class="p-3" src="img/pdf.svg" alt=""/>
</div>
</button>
</div>
<div class="relative">
@* <div class="w-full"> *@
@* <div class="flex flex-col space-y-4 xl:w-1/2 sm:w-full mx-auto"> *@
<object data="/getStatement" type="application/pdf" class="w-[28rem] h-[30rem] rounded-2xl">
<p class="text-center">Не удалось отобразить заявление, попробуйте скачать <a href="/getStatement">(тык)</a></p>
</object>
<div class="join w-full mt-4 flex gap-2">
<button onclick="exit_modal.showModal()" class="relative btn btn-primary rounded-full flex-grow-0 w-[3rem] h-[3rem]">
<img class="absolute p-3" src="img/exit.svg" alt=""/>
</button>
@* <button id="gen" class="btn rounded-full btn-primary flex-grow w-30">Сгенерировать</button> *@
@* <a href="otchislenie/result" class="btn rounded-full btn-primary flex-grow w-30">Сгенерировать</a> *@
<button onclick="SendToDirectorModal.showModal()"
class="btn btn-primary rounded-full flex-grow w-30">
Отправить директору
</button>
<a id="downloadPDF" target="_blank" href="/getStatement"
class="btn btn-primary bg-base-200 border-base-200 rounded-full flex-grow-0 w-[3rem]">
@* Скачать PDF *@<div class="absolute rounded-full w-12 h-12">
<img class="p-3" src="img/pdf.svg" alt=""/>
</div>
</a>
</div>
</div>
@* TODO: Сделать адаптив *@
@* <div class="card rounded-badge bg-base-200 p-4"> *@
@* <div class="flex flex-col space-y-4 mt-1"> *@
@* <button onclick="SendToDirectorModal.showModal()" *@
@* class="btn h-16 btn-primary rounded-full text-2xl relative"> *@
@* Отправить директору *@
@* </button> *@
@* <a id="downloadPDF" target="_blank" href="/getStatement" *@
@* class="btn h-16 btn-primary rounded-full text-2xl relative"> *@
@* Скачать PDF *@
@* <div class="absolute bg-base-200 rounded-full right-1 w-14 h-14"> *@
@* <img class="p-3" src="img/pdf.svg" alt=""/> *@
@* </div> *@
@* </a> *@
@* </div> *@
@* </div> *@
@* </div> *@
@* $1$ TODO: Сделать адаптив #1# *@
@* <div class="mt-9 flex flex-col space-y-4 lg:flex-row lg:space-x-4 lg:space-y-0 w-96 mx-auto" > *@
<div class="mt-9 flex flex-col space-y-4 w-96 mx-auto" >
<a href="/otchislenie/statement" class="btn w-96 h-14 btn-primary rounded-full text-2xl">
Назад
</a>
<a href="/" class="btn w-96 h-14 btn-primary rounded-full text-2xl">
Выход
</a>
</div>
@* <div class="mt-9 flex flex-col space-y-4 w-96 mx-auto"> *@
@* <a href="/otchislenie/statement" class="btn w-96 h-14 btn-primary rounded-full text-2xl"> *@
@* Назад *@
@* </a> *@
@* <a href="/" class="btn w-96 h-14 btn-primary rounded-full text-2xl"> *@
@* Выход *@
@* </a> *@
@* </div> *@
<div class="w-96 mx-auto mt-6">
<a id="congratulation" href="/otchislenie/congratulation" class="btn w-full h-16 btn-primary rounded-full text-2xl hidden">
<a id="congratulation" href="/otchislenie/congratulation"
class="btn w-full h-16 btn-primary rounded-full text-2xl hidden">
Страница поздравления
</a>
</div>
</div>
</div>

View File

@@ -1,8 +1,42 @@
@page "/otchislenie/statement"
@using Otchinslator.Components.Layout
@layout OtchislenieLayout
<a href="/otchislenie/result">Statement</a>
@using BlazorPageScript
@code {
}
<PageScript Src="./Components/Pages/Statement.razor.js" />
<dialog id="generateStatementModal" class="modal">
<div class="modal-box text-center justify-center">
<h3 class="text-lg content-center items-center font-bold select-none">Генерация</h3>
<p id="loadingAnim" class="py-4"><span class="loading w-[15rem] loading-ring sm:w-[20rem]"></span></p>
<div id="failBlock" class="hidden justify-center">
<div class="flex justify-center items-center">
<svg class="w-[15rem] h-[15rem]" fill="red" stroke="red" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<p class="text-red-500">Ошибка при генерации</p>
<p class="text-red-500">Попробуйте еще раз</p>
<div class="modal-action">
<form method="dialog">
<button class="btn">Закрыть</button>
</form>
</div>
</div>
</div>
</dialog>
<div class="relative">
<div class="text-center font-bold text-4xl md:text-5xl w-max absolute left-1/2 -top-1/3 transform -translate-x-1/2 italic"><br>Укажите причину</div>
<div class="flex flex-col space-y-4 w-96">
<textarea class="textarea textarea-bordered w-full h-96 resize-none" placeholder="Введите причину отчисления здесь..." name="statement"></textarea>
</div>
<div class="join w-full mt-4 flex gap-2">
<button onclick="exit_modal.showModal()" class="relative btn btn-primary rounded-full flex-grow-0 w-[3rem] h-[3rem]">
<img class="absolute p-3" src="img/exit.svg" alt=""/>
</button>
<button id="gen" class="btn rounded-full btn-primary flex-grow w-30">Сгенерировать</button>
@* <a href="otchislenie/result" class="btn rounded-full btn-primary flex-grow w-30">Сгенерировать</a> *@
<button onclick="info_modal.showModal()" class="btn btn-primary rounded-full flex-grow-0 w-[3rem]">?</button>
</div>
</div>

View File

@@ -0,0 +1,94 @@
export function onLoad() {
const statementField = document.querySelector('textarea[name="statement"]');
const generateButton = document.querySelector('button[id="gen"]');
const optionMapping = {
"Баклан": 1,
"Маг": 2,
"Спец": 3
};
function loadFromLocalStorage() {
const statement = localStorage.getItem('statement');
if (statement) {
statementField.value = statement;
}
}
generateButton.addEventListener('click', async () => {
hideLoadingModal(false);
console.log('Начата генерация заявления');
generateStatementModal.showModal();
const data = {
"phone": "+7" + localStorage.getItem('phoneNumber'),
"kurs": localStorage.getItem('kurs'),
"isFreeEducation": localStorage.getItem('paid') === "false",
"isOchno": false,
"speciality": optionMapping[localStorage.getItem('option')],
"reason": localStorage.getItem('statement')
}
try {
const response = await fetch("generateStatement", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.ok) {
console.log('Заявление успешно сгенерировано');
location.href='otchislenie/result';
} else {
hideLoadingModal();
console.log('Ошибка при генерации заявления');
console.log(response);
}
} catch (error) {
hideLoadingModal();
console.log('Ошибка при генерации заявления');
console.log(response);
}
});
function hideLoadingModal(hide = true) {
var loadingAnim = document.getElementById('loadingAnim');
var failBlock = document.getElementById('failBlock');
if (hide) {
loadingAnim.classList.add('hidden');
failBlock.classList.remove('hidden');
} else {
loadingAnim.classList.remove('hidden');
failBlock.classList.add('hidden');
}
}
function validateField() {
// если первая буква в lowerCase, то превращаем ее в upperCase
if (statementField.value.length > 0 && statementField.value[0] === statementField.value[0].toLowerCase()) {
statementField.value = statementField.value[0].toUpperCase() + statementField.value.slice(1);
}
// удаляем пробелы если их больше одного подряд
statementField.value = statementField.value.replace(/\s{2,}/g, ' ');
localStorage.setItem('statement', statementField.value);
if (statementField.value.length > 50) {
// удаляем пробелы в начале и в конце строки
statementField.value = statementField.value.trim();
generateButton.classList.remove('btn-disabled');
} else
generateButton.classList.add('btn-disabled');
}
statementField.addEventListener('input', validateField);
loadFromLocalStorage();
validateField();
}