parent
1f84edf535
commit
7d32805098
@ -0,0 +1,21 @@
|
||||
|
||||
export const doFetch = async function({ url, method = "GET", body = null, headers = {} }) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
body: !!body ? JSON.stringify(body) : undefined,
|
||||
mode: 'cors',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
...headers,
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${localStorage.getItem('jwt')}`
|
||||
}
|
||||
})
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
return { success: false, payload: error }
|
||||
}
|
||||
}
|
@ -1,64 +1,71 @@
|
||||
<script>
|
||||
import { fade } from 'svelte/transition';
|
||||
import Button from '../components/Button.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import Button from '../components/Button.svelte';
|
||||
import user from '../stores/user.js';
|
||||
|
||||
export let showLogin = true;
|
||||
let email= "";
|
||||
let password= "";
|
||||
let confirmPassword= "";
|
||||
let label = showLogin ? "Login" : "Sign up"
|
||||
let actionLabel = showLogin ? "Login" : "Sign up"
|
||||
let inverseLabel = !showLogin ? "Login" : "Sign up"
|
||||
let error = null;
|
||||
|
||||
function authenticate(){
|
||||
const toggle = () => showLogin = !showLogin;
|
||||
|
||||
|
||||
async function authenticate(){
|
||||
error = null;
|
||||
fetch("http://localhost:3000/v1/api/user/auth", {
|
||||
method: "POST",
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ email, password }),
|
||||
}).then(response => response.json())
|
||||
.then(({success, payload}) => {
|
||||
if (!success){
|
||||
error = payload;
|
||||
}
|
||||
})
|
||||
.catch(e => error = e.message);
|
||||
await user.login({ email, password });
|
||||
console.log(user);
|
||||
location.replace("/stats");
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
section {
|
||||
width: 33%;
|
||||
min-width: 500px;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply border-solid border-2 border-gray-700 ;
|
||||
@apply border-solid border-2 border-gray-700 flex-grow;
|
||||
}
|
||||
|
||||
form label {
|
||||
@apply flex flex-col py-2;
|
||||
}
|
||||
section div {
|
||||
@apply flex justify-between py-2 w-4/5;
|
||||
|
||||
form label span {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="w-full h-full flex justify-center flex-col content-center items-center" >
|
||||
<h2>{label} </h2>
|
||||
<section transition:fade class="flex flex-col p-5">
|
||||
<div >
|
||||
Email: <input id="email" bind:value={email}>
|
||||
</div>
|
||||
<div >
|
||||
Password: <input id="password" bind:value={password} type="password" >
|
||||
</div>
|
||||
<h2>{actionLabel}</h2>
|
||||
<form on:submit|preventDefault={authenticate} transition:fade class="flex flex-col p-5">
|
||||
<label>
|
||||
<span>Email:</span>
|
||||
<input id="email" bind:value={email}>
|
||||
</label>
|
||||
<label>
|
||||
<span>Password:</span>
|
||||
<input id="password" bind:value={password} type="password">
|
||||
</label>
|
||||
{#if !showLogin}
|
||||
<div>
|
||||
Confirm Password: <input id="confirm-password" bind:value={confirmPassword} type="password" >
|
||||
</div>
|
||||
<label>
|
||||
<span>Confirm Password:</span>
|
||||
<input id="confirm-password" bind:value={confirmPassword} type="password">
|
||||
</label>
|
||||
{/if}
|
||||
<section class="flex justify-end">
|
||||
<span class="pr-2"><Button>{actionLabel}</Button></span>
|
||||
<span ><Button on:button-click={toggle}>{inverseLabel}</Button></span>
|
||||
</section>
|
||||
{#if error}
|
||||
<section class="text-red-700">
|
||||
{error}
|
||||
</section>
|
||||
{/if}
|
||||
<Button on:button-click={authenticate}>{label}</Button>
|
||||
</section>
|
||||
{#if error}
|
||||
<section class="text-red-700">
|
||||
{error}
|
||||
</section>
|
||||
{/if}
|
||||
</form>
|
||||
</div>
|
@ -0,0 +1,49 @@
|
||||
import { query, operationStore, subscription } from '@urql/svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { doFetch } from '../../helpers';
|
||||
const defaultState = {loggedIn:false, loading:false, profile: null, error: null}
|
||||
const { subscribe, set, update } = writable(defaultState);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async function logStat({ type = "Weight", recordedTs, value }) {
|
||||
return await doFetch({
|
||||
url: 'http://localhost/v1/api/stats',
|
||||
method: 'PUT',
|
||||
body: {
|
||||
type,
|
||||
recordedTs,
|
||||
value
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const getStat = ({ start = '2020-01-01T00:00:00',types = ['Weight', 'Calories', 'Height'] }) =>
|
||||
operationStore(`
|
||||
query GetStats($types: [logtype!] = ["Weight"], $start: timestamp! = "2020-01-01T00:00:00") {
|
||||
stats_log(where: {
|
||||
logtype: {_in: $types },
|
||||
recordedts: {_gte: $start}
|
||||
},
|
||||
order_by: { recordedts: desc }) {
|
||||
value
|
||||
logtype
|
||||
recordedts
|
||||
id
|
||||
}
|
||||
}`,
|
||||
{ start, types },
|
||||
{
|
||||
requestPolicy: "cache-and-network",
|
||||
fetchOptions: {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('jwt')}`
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
export default { subscribe, logStat, getStat };
|
@ -0,0 +1,63 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { writable } from 'svelte/store';
|
||||
import { doFetch } from '../../helpers';
|
||||
|
||||
const defaultState = { loggedIn: false, loading: false, profile: null, error: null, token: null };
|
||||
|
||||
const { subscribe, set, update } = writable(defaultState);
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem('jwt');
|
||||
Cookies.remove('jwt', { path: '/', domain: 'localhost' });
|
||||
set(defaultState);
|
||||
location.pathname !== "/" && location.replace("/");
|
||||
}
|
||||
|
||||
const load = async () => {
|
||||
try {
|
||||
update(p => ({ ...p, loading: true}));
|
||||
|
||||
const {success, payload} = await doFetch({ url:"http://localhost:3000/v1/api/user" });
|
||||
|
||||
if (!success) {
|
||||
set({ ...defaultState, error: payload });
|
||||
logout();
|
||||
return
|
||||
}
|
||||
|
||||
update(() => ({ ...defaultState, loggedIn:true, profile: payload, token: localStorage.getItem('jwt') }));
|
||||
} catch (e) {
|
||||
set({ ...defaultState, error: e.message });
|
||||
logout();
|
||||
}
|
||||
}
|
||||
|
||||
const login = async ({ email, password }) => {
|
||||
try {
|
||||
update(p => ({ ...p, loading: true}));
|
||||
const { success, payload } = await doFetch({
|
||||
url: "http://localhost:3000/v1/api/user/auth",
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: { email, password }
|
||||
});
|
||||
|
||||
|
||||
if (!success) {
|
||||
set({ ...defaultState, error: payload });
|
||||
logout();
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
set({ ...defaultState, loggedIn:true, profile: payload.profile, token: payload.token });
|
||||
localStorage.setItem('jwt', payload.token)
|
||||
} catch (e) {
|
||||
set({ ...defaultState, error: e.message });
|
||||
console.trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
export default { subscribe, login, logout, load };
|
Loading…
Reference in new issue