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", "bulmaswatch": "^0.8.1",
"material-dynamic-colors": "^0.0.10", "material-dynamic-colors": "^0.0.10",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"pocketbase": "^0.7.3",
"svelte-spa-router": "^3.3.0" "svelte-spa-router": "^3.3.0"
}, },
"devDependencies": { "devDependencies": {
@ -885,6 +886,11 @@
"url": "https://github.com/sponsors/jonschlinkert" "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": { "node_modules/postcss": {
"version": "8.4.17", "version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", "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", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" "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": { "postcss": {
"version": "8.4.17", "version": "8.4.17",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",

View File

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

View File

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

View File

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

View File

@ -1,46 +1,29 @@
<script> <script>
import {link} from 'svelte-spa-router' import { link } from "svelte-spa-router";
import { activeNav } from '../store'; import { activeNav } from "../store";
let activeitem = $activeNav; let activeitem = $activeNav;
function updateActiveItem(num){
activeNav.set(num)
}
</script> </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"> <nav class="m l left">
<img class="circle" src="/vite.svg" alt="Favicon" />
<img class="circle" src="/vite.svg" alt="Favicon"> <a href="/" class:active={activeitem === 0} use:link>
<a href="/" class:active="{activeitem === 0}" on:click={()=>updateActiveItem(0)} use:link>
<i>home</i> <i>home</i>
<span>Home</span> <span>Home</span>
</a> </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> <i>payments</i>
<span>Budgets</span> <span>Budgets</span>
</a> </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> <i>timeline</i>
<span>Spending</span> <span>Spending</span>
</a> </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> <i>settings</i>
<span>Settings</span> <span>Settings</span>
</a> </a>
<div class="max"> <div class="max" />
</div>
<a href="/logout" use:link> <a href="/logout" use:link>
<i>logout</i> <i>logout</i>
<span>Logout</span> <span>Logout</span>
@ -48,20 +31,19 @@
</nav> </nav>
<nav class="s bottom"> <nav class="s bottom">
<a href="/" class:active={activeitem === 0} use:link>
<a href="/" class:active="{activeitem === 0}" on:click={()=>updateActiveItem(0)} use:link>
<i>home</i> <i>home</i>
<span>Home</span> <span>Home</span>
</a> </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> <i>payments</i>
<span>Budgets</span> <span>Budgets</span>
</a> </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> <i>timeline</i>
<span>Spending</span> <span>Spending</span>
</a> </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> <i>settings</i>
<span>Settings</span> <span>Settings</span>
</a> </a>
@ -70,3 +52,13 @@
<span>Logout</span> <span>Logout</span>
</a> </a>
</nav> </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> <script>
import BaseLayout from "../layouts/BaseLayout.svelte"; 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> </script>
<BaseLayout> <BaseLayout>
@ -9,33 +36,60 @@
</nav> </nav>
<div class="space" /> <div class="space" />
<hr /> <hr />
{#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"> <article class="responsive">
<table class="border medium-space"> <table class="border medium-space">
<thead> <thead>
<tr> <tr>
<th>Enabled</th>
<th>Name</th> <th>Name</th>
<th>Amount</th> <th>Amount</th>
<th /> <th />
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each FAKE_BUDGET_ITEMS as ITEM} {#each budgetItems as ITEM}
<tr> <tr>
<td>{ITEM.key}</td> <td>
<td>{ITEM.amount}</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> <td>
<nav class="right-align"> <nav class="right-align">
<button class="none">
<i>more_vert</i>
<div class="dropdown left no-wrap">
<!-- svelte-ignore a11y-missing-attribute --> <!-- svelte-ignore a11y-missing-attribute -->
<a>Edit</a> <a>
<i>edit</i>
</a>
<!-- svelte-ignore a11y-missing-attribute --> <!-- svelte-ignore a11y-missing-attribute -->
<a>Disable</a> <a>
<!-- svelte-ignore a11y-missing-attribute --> <i>delete</i>
<a>Delete</a> </a>
</div>
</button>
</nav> </nav>
</td> </td>
</tr> </tr>
@ -43,4 +97,5 @@
</tbody> </tbody>
</table> </table>
</article> </article>
{/if}
</BaseLayout> </BaseLayout>

View File

@ -1,10 +1,19 @@
<script> <script>
import { onMount } from "svelte";
import BaseLayout from "../layouts/BaseLayout.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> </script>
<BaseLayout> <BaseLayout>
<div> <div>
Home Welcome: {userName}
</div> </div>
</BaseLayout> </BaseLayout>

View File

@ -1,11 +1,14 @@
<script> <script>
import { replace } from 'svelte-spa-router'; import { replace } from 'svelte-spa-router';
import { isAuthed } from '../store';
import NoNavLayout from '../layouts/NoNavLayout.svelte'; 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("/"); replace("/");
isAuthed.set(true);
} }
</script> </script>
@ -17,12 +20,12 @@
<p>Username:</p> <p>Username:</p>
<div class="field border"> <div class="field border">
<input type="text"> <input bind:value={userName} type="text">
</div> </div>
<p>Password:</p> <p>Password:</p>
<div class="field border"> <div class="field border">
<input type="text"> <input bind:value={userPassword} type="password">
</div> </div>
<button class="responsive" on:click={doLogin}> <button class="responsive" on:click={doLogin}>

View File

@ -1,9 +1,12 @@
import { writable } from 'svelte/store'; 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 activeNav = writable(0);
export const authUserID = writable("");
export function resetStore() { export function resetStore() {
isAuthed.set(false); pbClient.authStore.clear();
activeNav.set(0); activeNav.set(0);
} }