learning_network_protocols/src/routes/login/+page.svelte

292 lines
6.6 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
import { progressStorage } from '$lib/utils/storage';
export let data; // { error } из load()
let activeTab = 'local';
let email = '';
let password = '';
let moodleUsername = '';
let moodlePassword = '';
let error = data?.error ?? '';
let loading = false;
let showPass = false;
let showMPass = false;
async function loginLocal() {
loading = true;
error = '';
try {
const res = await fetch('/auth/callback/local', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ email, password }),
});
if (res.url.includes('/login')) {
error = 'Неверный логин или пароль';
} else {
await progressStorage.transferToDB();
window.location.href = '/';
}
} catch {
error = 'Ошибка сети';
}
loading = false;
}
async function loginMoodle() {
loading = true;
error = '';
try {
const res = await fetch('/auth/callback/moodle', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ username: moodleUsername, password: moodlePassword }),
});
if (res.url.includes('/login')) {
error = 'Неверный логин или пароль Moodle';
} else {
await progressStorage.transferToDB();
window.location.href = '/';
}
} catch {
error = 'Ошибка сети';
}
loading = false;
}
</script>
<div class="page">
<div class="card">
<a href="/" class="close-btn" title="На главную"></a>
<h1>Вход</h1>
<div class="tabs">
<button class="tab" class:active={activeTab === 'local'}
on:click={() => { activeTab = 'local'; error = ''; }}>
Свой аккаунт
</button>
<button class="tab" class:active={activeTab === 'moodle'}
on:click={() => { activeTab = 'moodle'; error = ''; }}>
Войти через Moodle
</button>
</div>
{#if activeTab === 'local'}
<div class="form">
<input type="email" bind:value={email} placeholder="Email" />
<div class="pass-wrap">
<input type={showPass ? 'text' : 'password'}
bind:value={password} placeholder="Пароль"
autocomplete="current-password" />
<button type="button" class="eye" on:click={() => showPass = !showPass}>
{showPass ? '🙈' : '👁️'}
</button>
</div>
<button class="btn-primary" on:click={loginLocal} disabled={loading}>
{loading ? 'Вход...' : 'Войти'}
</button>
</div>
<p class="link">Нет аккаунта? <a href="/register">Зарегистрироваться</a></p>
{:else}
<div class="form">
<p class="hint">Введите логин и пароль от аккаунта Moodle</p>
<input type="text" bind:value={moodleUsername} placeholder="Логин Moodle" />
<div class="pass-wrap">
<input type={showMPass ? 'text' : 'password'}
bind:value={moodlePassword} placeholder="Пароль Moodle"
autocomplete="current-password" />
<button type="button" class="eye" on:click={() => showMPass = !showMPass}>
{showMPass ? '🙈' : '👁️'}
</button>
</div>
<button class="btn-moodle" on:click={loginMoodle} disabled={loading}>
{loading ? 'Проверка...' : '🎓 Войти через Moodle'}
</button>
</div>
<p class="link">
Нет аккаунта Moodle?
<a href="https://moodle-production-c39f.up.railway.app/login/signup.php"
target="_blank">Зарегистрироваться в Moodle</a>
</p>
{/if}
{#if error}
<div class="error">{error}</div>
{/if}
</div>
</div>
<style>
.page {
min-height:100vh;
display:flex;
align-items:center;
justify-content:center;
background:#f5f7fa;
}
.card {
position:relative;
background:white;
border-radius:12px;
padding:40px;
width:100%;
max-width:420px;
box-shadow:0 4px 20px rgba(0,0,0,.1);
}
.close-btn {
position:absolute;
top:14px;
right:14px;
font-size:1.1em;
color:#aaa;
text-decoration:none;
padding:4px 8px;
border-radius:50%;
transition:all .2s;
}
.close-btn:hover {
color:#555;
background:#f0f0f0;
}
h1 {
margin:0 0 24px;
color:#1565c0;
text-align:center;
}
.tabs {
display:flex;
border-bottom:2px solid #e0e0e0;
margin-bottom:24px;
}
.tab {
flex:1;
padding:10px;
border:none;
background:none;
cursor:pointer;
color:#888;
font-size:.95em;
border-bottom:2px solid transparent;
margin-bottom:-2px;
transition:all .2s;
}
.tab.active {
color:#1565c0;
border-bottom-color:#1565c0;
font-weight:bold;
}
.form {
display:flex;
flex-direction:column;
gap:12px;
}
input {
width:100%;
padding:11px 14px;
border:1px solid #ddd;
border-radius:8px;
font-size:1em;
outline:none;
box-sizing:border-box;
}
input:focus {
border-color:#2196F3;
}
.pass-wrap {
position:relative;
display:flex;
align-items:center;
}
.pass-wrap input {
padding-right:44px;
}
.eye {
position:absolute;
right:10px;
background:none;
border:none;
cursor:pointer;
font-size:1.1em;
padding:4px;
}
.btn-primary {
background:#2196F3;
color:white;
border:none;
padding:12px;
border-radius:8px;
cursor:pointer;
font-size:1em;
font-weight:500;
}
.btn-primary:hover:not(:disabled) {
background:#1565c0;
}
.btn-moodle {
background:#f98012;
color:white;
border:none;
padding:12px;
border-radius:8px;
cursor:pointer;
font-size:1em;
font-weight:500;
}
.btn-moodle:hover:not(:disabled) {
background:#e06b00;
}
button:disabled {
opacity:.6;
cursor:default;
}
.hint {
font-size:.85em;
color:#888;
margin:0;
text-align:center;
}
.link {
text-align:center;
margin-top:16px;
font-size:.9em;
color:#666;
}
.link a {
color:#2196F3;
text-decoration:none;
}
.error {
background:#ffebee;
color:#c62828;
padding:10px 14px;
border-radius:8px;
margin-top:16px;
font-size:.9em;
text-align:center;
}
</style>