Added user auth and clicker

This commit is contained in:
2023-10-30 13:26:48 -04:00
parent 8619c00a20
commit 995648dac3
11 changed files with 699 additions and 294 deletions

View File

@@ -1,47 +1,35 @@
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
import { ref, computed } from 'vue'
import Signup from './components/Signup.vue'
import Login from './components/Login.vue'
import Clicker from './components/Clicker.vue'
const routes = {
'/': Clicker,
'/signup': Signup,
'/login': Login,
'/button': Clicker,
}
const currentPath = ref(window.location.hash)
window.addEventListener('hashchange', () => {
currentPath.value = window.location.hash
})
const currentView = computed(() => {
return routes[currentPath.value.slice(1) || '/'] || NotFound
})
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="You did it!" />
</div>
</header>
<main>
<TheWelcome />
</main>
<Suspense>
<component :is="currentView" />
<template #fallback>
Loading...
</template>
</Suspense>
</template>
<style scoped>
header {
line-height: 1.5;
}
.logo {
display: block;
margin: 0 auto 2rem;
}
@media (min-width: 1024px) {
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
.logo {
margin: 0 2rem 0 0;
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
}
</style>

View File

@@ -0,0 +1,65 @@
<script setup>
import { ref } from 'vue'
async function get_clicks() {
const api_url = '/api/num'
let resp = await fetch(api_url)
console.log(resp)
if (resp.ok) {
let ans = await resp.json()
console.log(ans)
return ans
}
else {
window.location.hash = "/login"
return 'ERROR'
}
}
let clicks = await get_clicks()
const count = ref(clicks)
//const count = ref(-1)
async function click(ev) {
ev.preventDefault()
count.value = await get_clicks()
}
</script>
<template>
<main class="form-signin w-100 m-auto">
<p class="mt-5 mb-3 text-body">You have accessed this content {{ count }} times this session.</p>
<button type="submit" @click="click" class="btn btn-primary w-100 py-2">Refresh Content</button>
</main>
</template>
<style scoped>
/* html,
body {
height: 100%;
} */
.form-signin {
max-width: 330px;
padding: 1rem;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>

View File

@@ -1,44 +0,0 @@
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

View File

@@ -0,0 +1,95 @@
<script setup>
import { ref } from 'vue'
const user = ref('')
const pass = ref('')
async function login(ev) {
ev.preventDefault()
const api_url = '/api/auth'
const payload = { username: user.value, password: pass.value }
const fetch_options = {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json'
}
}
console.log(user.value)
console.log(pass.value)
console.log(api_url)
console.log(payload)
console.log(fetch_options)
let resp = await fetch(api_url, fetch_options)
console.log(resp)
if (resp.ok) {
let ans = await resp.json()
console.log(ans)
window.location.hash = "/"
} else {
user.value = ''
pass.value = ''
}
}
</script>
<template>
<main class="form-signin w-100 m-auto">
<form onsubmit="event.preventDefault();">
<!-- <img class="mb-4" src="../assets/brand/bootstrap-logo.svg" alt="" width="72" height="57"> -->
<svg class="bi me-2" width="72" height="57" role="img" viewBox="0 0 16 16">
<path d="M4.5 5a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1zM3 4.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z" />
<path
d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v1a2 2 0 0 1-2 2H8.5v3a1.5 1.5 0 0 1 1.5 1.5h5.5a.5.5 0 0 1 0 1H10A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5H.5a.5.5 0 0 1 0-1H6A1.5 1.5 0 0 1 7.5 10V7H2a2 2 0 0 1-2-2V4zm1 0v1a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1zm6 7.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5z" />
</svg>
<h1 class="h3 mb-3 fw-normal">Please sign in</h1>
<div class="form-floating">
<input type="email" v-model="user" class="form-control" id="floatingInput" placeholder="username">
<label for="floatingInput">Username</label>
</div>
<div class="form-floating">
<input type="password" v-model="pass" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
</div>
<div class="form-floating mb-3">
<a href="#/signup">Sign up</a>
</div>
<button type="submit" @click="login" class="btn btn-primary w-100 py-2">Sign in</button>
<p class="mt-5 mb-3 text-body-secondary">&copy; 2023</p>
</form>
</main>
</template>
<style scoped>
/* html,
body {
height: 100%;
} */
.form-signin {
max-width: 330px;
padding: 1rem;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>

View File

@@ -0,0 +1,105 @@
<script setup>
import { ref } from 'vue'
const user = ref('')
const pass = ref('')
const refe = ref('')
const err = ref('')
async function signup(ev) {
ev.preventDefault()
const api_url = '/api/user'
const payload = { username: user.value, password: pass.value, referral: refe.value }
const fetch_options = {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json'
}
}
console.log(user.value)
console.log(pass.value)
console.log(api_url)
console.log(payload)
console.log(fetch_options)
let resp = await fetch(api_url, fetch_options)
console.log(resp)
if (resp.ok) {
let ans = await resp.json()
console.log(ans)
window.location.hash = "/"
}
else {
err.value = "Username taken or invalid referral code"
}
}
</script>
<template>
<main class="form-signin w-100 m-auto my-auto">
<form onsubmit="event.preventDefault();">
<!-- <img class="mb-4" src="../assets/brand/bootstrap-logo.svg" alt="" width="72" height="57"> -->
<svg class="bi me-2" width="72" height="57" role="img" viewBox="0 0 16 16">
<path d="M4.5 5a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1zM3 4.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z" />
<path
d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v1a2 2 0 0 1-2 2H8.5v3a1.5 1.5 0 0 1 1.5 1.5h5.5a.5.5 0 0 1 0 1H10A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5H.5a.5.5 0 0 1 0-1H6A1.5 1.5 0 0 1 7.5 10V7H2a2 2 0 0 1-2-2V4zm1 0v1a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1zm6 7.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5z" />
</svg>
<h1 class="h3 mb-3 fw-normal">Sign up</h1>
<div class="form-floating">
<input type="text" v-model="user" class="form-control" id="floatingInput" placeholder="username">
<label for="floatingInput">Username</label>
</div>
<div class="form-floating">
<input type="password" v-model="pass" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
</div>
<div class="form-floating">
<input type="text" v-model="refe" class="form-control" id="floatingInput" placeholder="">
<label for="floatingInput">Referral Code</label>
</div>
<div class="form-floating">
<p> {{ err }} </p>
</div>
<div class="form-floating mb-3">
Already have an account?
<a href="#/login">Log in</a>
</div>
<button type="submit" @click="signup" class="btn btn-primary w-100 py-2">Sign up</button>
<p class="mt-5 mb-3 text-body-secondary">&copy; 2023</p>
</form>
</main>
</template>
<style scoped>
/* html,
body {
height: 100%;
} */
.form-signin {
max-width: 330px;
padding: 1rem;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>

View File

@@ -1,88 +0,0 @@
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
you need to test your components and web pages, check out
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
<a href="https://on.cypress.io/component" target="_blank" rel="noopener"
>Cypress Component Testing</a
>.
<br />
More instructions are available in <code>README.md</code>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
Discord server, or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also subscribe to
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
the official
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
twitter account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

View File

@@ -1,87 +0,0 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
position: relative;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>