Added pocket base.

This commit is contained in:
Thomas Cole 2022-10-14 14:20:25 -04:00
parent 4dd4c22db6
commit 402c65fc90
9 changed files with 200 additions and 101 deletions

11
package-lock.json generated
View File

@ -14,6 +14,7 @@
"bulmaswatch": "^0.8.1",
"material-dynamic-colors": "^0.0.10",
"normalize.css": "^8.0.1",
"pocketbase": "^0.7.3",
"svelte-spa-router": "^3.3.0"
},
"devDependencies": {
@ -885,6 +886,11 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pocketbase": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.7.3.tgz",
"integrity": "sha512-sMbj6uw0f/u9xALsow9b2xlA/6vCB+R0DVswldTxxSBY+HQNz2EyLW2jQu8sMYwo7W0OF2VPyV2Aa+RlhyPoLQ=="
},
"node_modules/postcss": {
"version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",
@ -1668,6 +1674,11 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"pocketbase": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.7.3.tgz",
"integrity": "sha512-sMbj6uw0f/u9xALsow9b2xlA/6vCB+R0DVswldTxxSBY+HQNz2EyLW2jQu8sMYwo7W0OF2VPyV2Aa+RlhyPoLQ=="
},
"postcss": {
"version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",

View File

@ -20,6 +20,7 @@
"bulmaswatch": "^0.8.1",
"material-dynamic-colors": "^0.0.10",
"normalize.css": "^8.0.1",
"pocketbase": "^0.7.3",
"svelte-spa-router": "^3.3.0"
}
}

View File

@ -1,36 +1,60 @@
<script>
import Router from 'svelte-spa-router';
import { replace } from 'svelte-spa-router';
import Router from "svelte-spa-router";
import { replace, location } from "svelte-spa-router";
import { isAuthed } from './store';
import Home from './routes/Home.svelte';
import NotFound from './routes/NotFound.svelte';
import Budgets from './routes/Budgets.svelte';
import Settings from './routes/Settings.svelte';
import Timeline from './routes/Timeline.svelte'
import Login from './routes/Login.svelte';
import Logout from './routes/Logout.svelte';
import { onMount } from 'svelte';
import { pbClient, activeNav } from "./store";
import Home from "./routes/Home.svelte";
import NotFound from "./routes/NotFound.svelte";
import Budgets from "./routes/Budgets.svelte";
import Settings from "./routes/Settings.svelte";
import Timeline from "./routes/Timeline.svelte";
import Login from "./routes/Login.svelte";
import Logout from "./routes/Logout.svelte";
import { onMount } from "svelte";
import { authUserID } from "./store";
const routes = {
'/': Home,
'/timeline': Timeline,
"/budgets": Budgets,
'/settings': Settings,
'/login': Login,
'/logout': Logout,
'*': NotFound,
}
onMount(()=> {
console.log($isAuthed)
if(!$isAuthed){
replace('/login')
}
})
"/": Home,
"/timeline": Timeline,
"/budgets": Budgets,
"/settings": Settings,
"/login": Login,
"/logout": Logout,
"*": NotFound,
};
location.subscribe((value) => {
switch (value) {
case "/":
activeNav.set(0);
break;
case "/budgets":
activeNav.set(1);
break;
case "/timeline":
activeNav.set(2);
break;
case "/settings":
activeNav.set(3);
break;
default:
break;
}
});
onMount(() => {
if (
!pbClient.authStore.isValid ||
localStorage.getItem("pocketbase_auth") == null
) {
replace("/login");
}
authUserID.set(
JSON.parse(localStorage.getItem("pocketbase_auth")).model.id
);
});
</script>
<Router {routes}/>
<Router {routes} />

View File

@ -6,6 +6,7 @@ export const FAKE_BUDGET_ITEMS = [
"isEnabled": true,
"entries":[
{
"budget_item_id": "",
"name": "Test Entry",
"amount": 20,
"description": "Extra info if wanted",

View File

@ -1,46 +1,29 @@
<script>
import {link} from 'svelte-spa-router'
import { activeNav } from '../store';
let activeitem = $activeNav;
function updateActiveItem(num){
activeNav.set(num)
}
import { link } from "svelte-spa-router";
import { activeNav } from "../store";
let activeitem = $activeNav;
</script>
<style>
@media only screen and (max-width: 600px){
.m:not(.s), .l:not(.s), .m.l:not(.s) {
display: none;
}
}
</style>
<nav class="m l left">
<img class="circle" src="/vite.svg" alt="Favicon">
<a href="/" class:active="{activeitem === 0}" on:click={()=>updateActiveItem(0)} use:link>
<img class="circle" src="/vite.svg" alt="Favicon" />
<a href="/" class:active={activeitem === 0} use:link>
<i>home</i>
<span>Home</span>
</a>
<a href="/budgets" class:active="{activeitem === 1}" on:click={()=>updateActiveItem(1)} use:link>
<a href="/budgets" class:active={activeitem === 1} use:link>
<i>payments</i>
<span>Budgets</span>
</a>
<a href="/timeline" class:active="{activeitem === 2}" on:click={()=>updateActiveItem(2)} use:link>
<a href="/timeline" class:active={activeitem === 2} use:link>
<i>timeline</i>
<span>Spending</span>
</a>
<a href="/settings" class:active="{activeitem === 3}" on:click={()=>updateActiveItem(3)} use:link>
<a href="/settings" class:active={activeitem === 3} use:link>
<i>settings</i>
<span>Settings</span>
</a>
<div class="max">
</div>
<div class="max" />
<a href="/logout" use:link>
<i>logout</i>
<span>Logout</span>
@ -48,20 +31,19 @@
</nav>
<nav class="s bottom">
<a href="/" class:active="{activeitem === 0}" on:click={()=>updateActiveItem(0)} use:link>
<a href="/" class:active={activeitem === 0} use:link>
<i>home</i>
<span>Home</span>
</a>
<a href="/budgets" class:active="{activeitem === 1}" on:click={()=>updateActiveItem(1)} use:link>
<a href="/budgets" class:active={activeitem === 1} use:link>
<i>payments</i>
<span>Budgets</span>
</a>
<a href="/timeline" class:active="{activeitem === 2}" on:click={()=>updateActiveItem(2)} use:link>
<a href="/timeline" class:active={activeitem === 2} use:link>
<i>timeline</i>
<span>Spending</span>
</a>
<a href="/settings" class:active="{activeitem === 3}" on:click={()=>updateActiveItem(3)} use:link>
<a href="/settings" class:active={activeitem === 3} use:link>
<i>settings</i>
<span>Settings</span>
</a>
@ -70,3 +52,13 @@
<span>Logout</span>
</a>
</nav>
<style>
@media only screen and (max-width: 600px) {
.m:not(.s),
.l:not(.s),
.m.l:not(.s) {
display: none;
}
}
</style>

View File

@ -1,6 +1,33 @@
<script>
import BaseLayout from "../layouts/BaseLayout.svelte";
import { FAKE_BUDGET_ITEMS } from "../fakeData";
import { onMount } from "svelte";
import { pbClient, authUserID } from "../store";
let budgetItems = [];
async function disableBudgetItem(recordID) {
await pbClient.records.update("eo2i6pm5ldu4tsm_budget_items", recordID, {
isEnabled: false,
});
fetchData();
}
async function enableBudgetItem(recordID) {
await pbClient.records.update("eo2i6pm5ldu4tsm_budget_items", recordID, {
isEnabled: true,
});
fetchData();
}
async function fetchData() {
const items = await pbClient.records.getList($authUserID + "_budget_items");
budgetItems = items.items;
}
onMount(async () => {
fetchData();
});
</script>
<BaseLayout>
@ -9,38 +36,66 @@
</nav>
<div class="space" />
<hr />
<article class="responsive">
<table class="border medium-space">
<thead>
<tr>
<th>Name</th>
<th>Amount</th>
<th />
</tr>
</thead>
<tbody>
{#each FAKE_BUDGET_ITEMS as ITEM}
{#if budgetItems.length == 0}
<div class="padding absolute center middle">
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y-missing-content -->
<a class="loader" />
</div>
{:else}
<article class="responsive">
<table class="border medium-space">
<thead>
<tr>
<td>{ITEM.key}</td>
<td>{ITEM.amount}</td>
<td>
<nav class="right-align">
<button class="none">
<i>more_vert</i>
<div class="dropdown left no-wrap">
<!-- svelte-ignore a11y-missing-attribute -->
<a>Edit</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a>Disable</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a>Delete</a>
</div>
</button>
</nav>
</td>
<th>Enabled</th>
<th>Name</th>
<th>Amount</th>
<th />
</tr>
{/each}
</tbody>
</table>
</article>
</thead>
<tbody>
{#each budgetItems as ITEM}
<tr>
<td>
<label class="switch">
{#if ITEM.isEnabled}
<input
type="checkbox"
checked
on:change={() => disableBudgetItem(ITEM.id)}
/>
{:else}
<input
type="checkbox"
on:change={() => enableBudgetItem(ITEM.id)}
/>
{/if}
<span />
</label>
</td>
<td>
<p>{ITEM.name}</p>
</td>
<td>
<p>{ITEM.amount}</p>
</td>
<td>
<nav class="right-align">
<!-- svelte-ignore a11y-missing-attribute -->
<a>
<i>edit</i>
</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a>
<i>delete</i>
</a>
</nav>
</td>
</tr>
{/each}
</tbody>
</table>
</article>
{/if}
</BaseLayout>

View File

@ -1,10 +1,19 @@
<script>
import { onMount } from "svelte";
import BaseLayout from "../layouts/BaseLayout.svelte";
import { pbClient, authUserID } from '../store'
let userName = "";
onMount(async ()=>{
const user = await pbClient.users.getOne($authUserID);
userName = user.profile.name;
})
</script>
<BaseLayout>
<div>
Home
Welcome: {userName}
</div>
</BaseLayout>

View File

@ -1,11 +1,14 @@
<script>
import { replace } from 'svelte-spa-router';
import { isAuthed } from '../store';
import NoNavLayout from '../layouts/NoNavLayout.svelte';
import { pbClient, authUserID } from '../store';
function doLogin(){
let userName = "";
let userPassword = "";
async function doLogin(){
const userAuthData = await pbClient.users.authViaEmail(userName, userPassword);
replace("/");
isAuthed.set(true);
}
</script>
@ -17,12 +20,12 @@
<p>Username:</p>
<div class="field border">
<input type="text">
<input bind:value={userName} type="text">
</div>
<p>Password:</p>
<div class="field border">
<input type="text">
<input bind:value={userPassword} type="password">
</div>
<button class="responsive" on:click={doLogin}>

View File

@ -1,9 +1,12 @@
import { writable } from 'svelte/store';
import PocketBase from 'pocketbase';
export const pbClient = new PocketBase('https://pb.thomaspcole.com');
export const isAuthed = writable(false);
export const activeNav = writable(0);
export const authUserID = writable("");
export function resetStore() {
isAuthed.set(false);
pbClient.authStore.clear();
activeNav.set(0);
}