in the middle of refactor, just to keep track

This commit is contained in:
ed barz 2023-05-30 21:34:02 +02:00
parent ccc79e75d9
commit 03de896ccb
17 changed files with 474 additions and 27 deletions

View File

@ -36,3 +36,71 @@ npm run build
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
////////////////
Right now, my signup page is set up like that:
<svelte:head>
<title>Sign Up</title>
</svelte:head>
<script>
import { signup } from '$lib/api';
import Modal from '$components/Modal.svelte';
let showModal = true;
let modalMessage = 'Test message';
let email = '';
let password = '';
async function handleSignup() {
try {
const user = await signup(email, password);
alert('Signup successful');
} catch (err) {
alert('Signup failed because of : ' + err);
}
}
function closeModal() {
showModal = false;
}
</script>
<main>
<div class="colonel">
<input type="email" bind:value={email} placeholder="Email">
<input type="password" bind:value={password} placeholder="Password">
<button class="btn-fly" on:click={handleSignup}>Sign Up</button>
</div>
{#if showModal}
<Modal {modalMessage} on:close={closeModal} />
{/if}
</main>
And input is set up like that in styles/forms.scss:
input[type=text], input[type=password], input[type=email], input[type=number], input[type=date], select {
padding: 12px 0px;
margin: 8px 0;
box-sizing: border-box;
border: none;
border-bottom: 5px solid $fg-color;
background-color: $bg-color;
color: $fg-color;
font-size: 1.2rem;
font-weight: 400;
&:focus {
outline: none;
border-bottom: 5px solid $red;
}
}
So the email field has a red border on bottom when focused.
I would like that borer to become green when the email is valid.

80
package-lock.json generated
View File

@ -8,8 +8,10 @@
"name": "brz9front",
"version": "0.0.1",
"dependencies": {
"cookie": "^0.5.0",
"dotenv": "^16.0.3",
"normalize.css": "^8.0.1"
"normalize.css": "^8.0.1",
"svelte-navigator": "^3.2.2"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
@ -1012,7 +1014,6 @@
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
@ -1048,6 +1049,11 @@
}
}
},
"node_modules/dedent-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ=="
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@ -1782,6 +1788,14 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dependencies": {
"tslib": "^2.0.3"
}
},
"node_modules/magic-string": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
@ -1866,6 +1880,15 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -1948,6 +1971,15 @@
"node": ">=6"
}
},
"node_modules/pascal-case": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@ -2377,7 +2409,6 @@
"version": "3.59.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.1.tgz",
"integrity": "sha512-pKj8fEBmqf6mq3/NfrB9SLtcJcUvjYSWyePlfCqN9gujLB25RitWK8PvFzlwim6hD/We35KbPlRteuA6rnPGcQ==",
"dev": true,
"engines": {
"node": ">= 8"
}
@ -2419,6 +2450,31 @@
"svelte": ">=3.19.0"
}
},
"node_modules/svelte-navigator": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/svelte-navigator/-/svelte-navigator-3.2.2.tgz",
"integrity": "sha512-Xio4ohLUG1nQJ+ENNbLphXXu9L189fnI1WGg+2Q3CIMPe8Jm2ipytKQthdBs8t0mN7p3Eb03SE9hq0xZAqwQNQ==",
"hasInstallScript": true,
"dependencies": {
"svelte2tsx": "^0.1.151"
},
"peerDependencies": {
"svelte": "3.x"
}
},
"node_modules/svelte2tsx": {
"version": "0.1.193",
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.1.193.tgz",
"integrity": "sha512-vzy4YQNYDnoqp2iZPnJy7kpPAY6y121L0HKrSBjU/IWW7DQ6T7RMJed2VVHFmVYm0zAGYMDl9urPc6R4DDUyhg==",
"dependencies": {
"dedent-js": "^1.0.1",
"pascal-case": "^3.1.1"
},
"peerDependencies": {
"svelte": "^3.24",
"typescript": "^4.1.2"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -2456,6 +2512,11 @@
"node": ">=6"
}
},
"node_modules/tslib": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz",
"integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA=="
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -2480,6 +2541,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/undici": {
"version": "5.22.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",

View File

@ -24,7 +24,9 @@
},
"type": "module",
"dependencies": {
"cookie": "^0.5.0",
"dotenv": "^16.0.3",
"normalize.css": "^8.0.1"
"normalize.css": "^8.0.1",
"svelte-navigator": "^3.2.2"
}
}

View File

@ -0,0 +1,5 @@
<!-- Footer.svelte -->
<footer class="page-footer">
<p>Copyright © 2023 My Website</p>
</footer>

View File

@ -0,0 +1,59 @@
<!-- Header.svelte -->
<script>
export let isLoggedIn = false;
export let showUserNav = true;
export let showHome = true;
</script>
<header>
<nav>
<div class="nav-left">
{#if showHome}
<a href="/">
<span class="brz9-icon-home"></span>
</a>
{:else}
<span></span>
{/if}
</div>
<div class="nav-right">
{#if showUserNav}
{#if isLoggedIn}
<a href="/profile">
<span class="brz9-icon-user"></span>
</a>
<a href="/logout">
<span class="brz9-icon-exit"></span>
</a>
{:else}
<a href="/login">
<span class="brz9-icon-enter"></span>
</a>
{/if}
{:else}
<span></span>
{/if}
</div>
</nav>
</header>
<style>
header nav {
display: flex;
justify-content: space-between;
padding: 1em;
font-size: 1.5rem;
}
.nav-left, .nav-right {
display: flex;
}
a {
margin-right: 1em;
text-decoration: none;
color: inherit;
}
</style>

View File

@ -16,6 +16,7 @@
</header>
<div class="modal-content">
<p>{modalMessage}</p>
<slot></slot>
</div>
</div>
@ -49,6 +50,7 @@
align-items: center;
.modal-content {
font-size: 1.6rem;
padding: 30px;
}
}
button {

View File

@ -26,6 +26,7 @@ export async function login(email, password) {
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({
email: email,
password: password
@ -38,6 +39,9 @@ export async function login(email, password) {
}
// Here you could do something with the login response, like storing a user token
//localStorage.setItem('userToken', data.token);
//cookie.set('userToken', data.token, { expires: 7 });
//cookie.set("check", "check", { expires: 7 })
console.log(data)
return data;
}

View File

@ -3,6 +3,7 @@
</svelte:head>
<script>
import Header from '$components/Header.svelte';
let text = '';
const apiUrl = import.meta.env.VITE_API_URL;
@ -38,8 +39,9 @@
}
// Fetch notes when the component is first rendered
fetchNotes();
export let showHome = false;
</script>
<Header {showHome}/>
<main>
<h1>Welcome to SvelteKit</h1>
@ -53,7 +55,7 @@
<input bind:value={text} type="text" placeholder="Enter note text" />
<button on:click={createNote}>Create Note</button>
<br>
<button on:click={fetchNotes}>Refresh Notes</button>
<button class="blob-button" on:click={fetchNotes}>Refresh Notes</button>
<ul>
{#each notes as note}
@ -63,4 +65,12 @@
<h4>Just to check, the current API endpoint is : {apiUrl}</h4>
</main>
</main>
<style>
ul li {
max-width: 300px;
line-break: anywhere;
}
</style>

View File

@ -0,0 +1,48 @@
import { redirect } from "@sveltejs/kit";
import { login } from '$lib/api';
export const load = async (event) => {
console.log("hello from backend")
const sessionID = event.cookies.get('sessionID');
if (sessionID) {
throw redirect('/profile');
}
};
export const actions = {
default: async (event) => {
const formData = await event.request.formData();
const email = formData.get('email');
const password = formData.get('password');
const apiUrl = import.meta.env.VITE_API_URL;
const res = await fetch(apiUrl + '/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({
email: email,
password: password
})
});
if (res.ok) {
console.log("ok")
return redirect('/profile');
} else {
console.log("not ok")
const error = await res.json();
return {
status: 400,
redirect: '/login',
body: { error }
};
}
},
};

View File

@ -4,27 +4,66 @@
<script>
import { login } from '$lib/api';
import { isValidEmail } from '$lib/utils';
import Modal from '$components/Modal.svelte';
import Header from '$components/Header.svelte';
import Footer from '$components/Footer.svelte';
import { navigate } from 'svelte-navigator';
let showModal = false;
let modalMessage = 'Test message';
let email = '';
let password = '';
async function handleLogin() {
return;
if (!isValidEmail(email)){
modalMessage = "Please enter the email address you used to sign up.";
showModal = true;
return;
}
try {
const user = await login(email, password);
alert('Login successful');
navigate('/profile');
//reload the page
location.reload();
} catch (err) {
alert('Login failed because of : ' + err);
modalMessage = err;
showModal = true;
}
}
function closeModal() {
showModal = false;
}
let showUserNav = false;
</script>
<Header {showUserNav} />
<main>
<form class="colonel">
<form class="colonel" on:submit={handleLogin}>
<input type="email" placeholder="Email" bind:value={email} required>
<input type="password" placeholder="Password" bind:value={password} required>
<input type="password" placeholder="P@s5word" bind:value={password} required>
<button class="btn-fly" on:click={handleLogin}>Log in</button>
<button type="submit" class="btn-fly">Log in</button>
</form>
</main>
<form class="colonel" method="POST">
<input type="email" name="email" placeholder="Email" bind:value={email} required>
<input type="password" name="password" placeholder="P@s5word" bind:value={password} required>
<button type="submit" class="btn-fly">Log in</button>
</form>
{#if showModal}
<Modal on:close={closeModal}>
<p>{modalMessage}</p>
</Modal>
{/if}
</main>
<Footer />

View File

@ -0,0 +1,22 @@
<script>
import { onMount } from 'svelte';
//import { getUserData } from '$lib/api'; // This function should send a request to your server to get the user's data.
//let user;
//onMount(async () => {
// user = await getUserData();
//});
</script>
<h2>Profile</h2>
<!-- Path: src/routes/profile/+page.svelte
{#if user}
<h1>Welcome, {user.name}!</h1>
<p>Your email is {user.email}.</p>
{:else}
<p>Loading...</p>
{/if}
-->

View File

@ -6,34 +6,49 @@
import { signup } from '$lib/api';
import { isValidEmail, isValidPassword } from '$lib/utils';
import Modal from '$components/Modal.svelte';
import Header from '$components/Header.svelte';
import Footer from '$components/Footer.svelte';
import { navigate } from 'svelte-navigator';
let showModal = true;
let showModal = false;
let modalMessage = 'Test message';
let email = '';
let password = '';
async function handleSignup() {
if (!isValidEmail(email)){
modalMessage = 'This: "'+ email +'" does not look like a valid email address. Imagine you lose your password, how would you get it back? We need to send you an email. Without a valid email address, that will be difficult.';
showModal = true;
return;
}
if (!isValidPassword(password)){
modalMessage = 'My bad, I thought the UI was clear. Password must be at least 8 characters long with at least one number, one lowercase letter, one uppercase letter and one special character (try again until the line is no longer red, you silly goose)';
showModal = true;
return;
}
try {
const user = await signup(email, password);
alert('Signup successful');
sessionStorage.setItem('formSubmitted', 'true');
navigate('/signup/success');
} catch (err) {
alert('Signup failed because of : ' + err);
modalMessage = err;
showModal = true;
}
}
async function handleSubmit(event) {
event.preventDefault(); // prevent the form from refreshing the page
await handleSignup();
}
function closeModal() {
showModal = false;
}
let showUserNav = false;
</script>
<Header {showUserNav} />
<main>
<form class="colonel" on:submit={handleSubmit}>
<form class="colonel" on:submit={handleSignup}>
<input
type="email"
bind:value={email}
@ -46,11 +61,14 @@
placeholder="Pas$w0rd"
class:valid={isValidPassword(password)}
>
<button type="submit" class="btn-fly" on:click={handleSignup}>Sign Up</button>
<button type="submit" class="btn-fly">Sign Up</button>
</form>
{#if showModal}
<Modal {modalMessage} on:close={closeModal} />
<Modal on:close={closeModal}>
<p>{modalMessage}</p>
</Modal>
{/if}
</main>
</main>
<Footer />

View File

@ -0,0 +1,33 @@
<script>
import { onMount } from 'svelte';
import { navigate } from 'svelte-navigator';
import Header from '$components/Header.svelte';
import Footer from '$components/Footer.svelte';
let formSubmitted = false;
onMount(() => {
formSubmitted = sessionStorage.getItem('formSubmitted') === 'true';
if (!formSubmitted) {
navigate('/');
//load the page again
location.reload();
} else {
// Clear the flag from session storage after checking it
//sessionStorage.removeItem('formSubmitted');
}
});
let showUserNav = false;
</script>
{#if formSubmitted}
<Header {showUserNav}/>
<main>
<h1>Signup successful!</h1>
<p>You can now check your inbox to activate your account.</p>
</main>
<Footer />
{/if}

47
src/styles/blob.scss Normal file
View File

@ -0,0 +1,47 @@
@function random-range($min, $max) {
@return random() * ($max - $min) + $min + '%';
}
@mixin random-blob-shape {
$x1: random-range(40, 60);
$x2: random-range(10, 30);
$x3: random-range(50, 70);
$x4: random-range(20, 40);
$y1: random-range(30, 70);
$y2: random-range(20, 40);
$y3: random-range(60, 80);
$y4: random-range(30, 70);
$horizontalRadii: $x1 $x2 $x3 $x4;
$verticalRadii: $y1 $y2 $y3 $y4;
border-radius: #{$horizontalRadii} / #{$verticalRadii};
}
.blob-button {
background-color: #ff7f50;
color: #fff;
padding: 25px;
font-size: 16px;
border: none;
cursor: pointer;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
transition: transform 0.3s ease;
@include random-blob-shape;
/*animation: blob-animation 4s infinite ease-in-out;*/
}
/*
@keyframes blob-animation {
0% {
border-radius: 50% 20% 60% 40% / 60% 30% 70% 40%;
}
50% {
border-radius: 70% 30% 50% 20% / 40% 60% 20% 60%;
}
100% {
border-radius: 50% 20% 60% 40% / 60% 30% 70% 40%;
}
}
*/

View File

@ -31,4 +31,4 @@ input[type=text], input[type=password], input[type=email], input[type=number], i
&.valid {
border-bottom: 5px solid $fg-color;
}
}
}

View File

@ -1,3 +1,13 @@
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex-grow: 1;
}
.container {
display: flex;
flex-wrap: wrap;
@ -43,4 +53,9 @@
*{
margin-top: 50px;
}
}
footer.page-footer {
text-align: center;
margin-bottom: 20px;
}

View File

@ -4,3 +4,4 @@
@import 'layout';
@import 'responsive';
@import 'forms';
@import 'blob';