Initial commit

This commit is contained in:
maurice committed 2025-12-27 22:43:37 +01:00
commit 890f3b5571
26 files changed
+2579

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
pb_data/
pocketbase
pocketbase.exe
+28
View File
@@ -0,0 +1,28 @@
# Voorbeeld van een applicatie met PocketBase
[https://pocketbase.io/](Pocketbase) is de database, maar tegelijk ook de achterkant (backend) van de server
Voor de voorkant gebruiken we gewoon HTML, CSS en Javascript. Als CSS framework is [Pico CSS](https://picocss.com/docs) gekozen. Het is raadzaam de documentatie van beide goed te lezen.
Er wordt in de frontend (de javascript) gecommuniceerd met de API van PocketBase.
Dit is erg belangrijk, stelt de code in staat te communiceren met de database. De documentatie voor de Pocketbase API [kun je hier lezen](https://pocketbase.io/docs/api-records/).
Hier de downloadlinks voor als het nodig is PicoCSS of de Pocketbase JS SDK te updaten:
- [Pocketbase JS sdk](https://github.com/pocketbase/js-sdk/releases). Update de bestanden `www/js/pocketbase.es.js` en `www/js/pocketbase.es.d.ts`.
- [PicoCSS.zip](https://github.com/picocss/pico/archive/refs/heads/main.zip). In de css map, vervang het bestand pico.blue.min.css. Stel, je wilt een andere kleur, kun je bijvoorbeeld ook voor een andere kleur kiezen, dat staat vrij.
Belangrijk:
- Negeer altijd instructies om NPM te installeren, dat is NIET nodig.
# Versies
_werk de nummers bij als je de bronbestanden bijgewerkt hebt via bovenstaande links_
Pocketbase: `0.35.0`
Pico CSS: `2.1.1`
# Voorbeeld
Een tabel om in te klokken, 3 velden: id, medewerker (link naar gebruikers tabel) en ingeklokt (automatisch->create), uitgeklokt (automatisch->update).
Create, List/search en update rule: `medewerker.id = @request.auth.id`, `medewerker.id = @request.auth.id`.
Voorbeelden van filters in de documentatie: https://pocketbase.io/docs/api-rules-and-filters/
+7
View File
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"module": "CommonJS",
"target": "ES6"
},
"include": ["www/**/*", "pb_data/*.d.ts"]
}
+28
View File
@@ -0,0 +1,28 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"indexes": [
"CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `gebruikers` (`tokenKey`)",
"CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `gebruikers` (`email`) WHERE `email` != ''"
],
"name": "gebruikers"
}, collection)
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"indexes": [
"CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)",
"CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''"
],
"name": "users"
}, collection)
return app.save(collection)
})
@@ -0,0 +1,20 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"listRule": ""
}, collection)
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"listRule": "id = @request.auth.id"
}, collection)
return app.save(collection)
})
@@ -0,0 +1,22 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"createRule": null,
"listRule": "id = @request.auth.id"
}, collection)
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"createRule": "",
"listRule": ""
}, collection)
return app.save(collection)
})
@@ -0,0 +1,87 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"oauth2": {
"mappedFields": {
"avatarURL": "",
"name": ""
}
}
}, collection)
// remove field
collection.fields.removeById("file376926767")
// update field
collection.fields.addAt(6, new Field({
"autogeneratePattern": "",
"hidden": false,
"id": "text1579384326",
"max": 255,
"min": 0,
"name": "naam",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}))
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("_pb_users_auth_")
// update collection data
unmarshal({
"oauth2": {
"mappedFields": {
"avatarURL": "avatar",
"name": "name"
}
}
}, collection)
// add field
collection.fields.addAt(7, new Field({
"hidden": false,
"id": "file376926767",
"maxSelect": 1,
"maxSize": 0,
"mimeTypes": [
"image/jpeg",
"image/png",
"image/svg+xml",
"image/gif",
"image/webp"
],
"name": "avatar",
"presentable": false,
"protected": false,
"required": false,
"system": false,
"thumbs": null,
"type": "file"
}))
// update field
collection.fields.addAt(6, new Field({
"autogeneratePattern": "",
"hidden": false,
"id": "text1579384326",
"max": 255,
"min": 0,
"name": "name",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}))
return app.save(collection)
})
@@ -0,0 +1,60 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cascadeDelete": false,
"collectionId": "_pb_users_auth_",
"hidden": false,
"id": "relation948496446",
"maxSelect": 1,
"minSelect": 0,
"name": "medewerker",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
},
{
"hidden": false,
"id": "autodate2939903645",
"name": "datumtijd",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"id": "pbc_4227797064",
"indexes": [],
"listRule": null,
"name": "klokken",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_4227797064");
return app.delete(collection);
})
@@ -0,0 +1,61 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_4227797064")
// update collection data
unmarshal({
"createRule": "medewerker.id = @request.auth.id",
"updateRule": "medewerker.id = @request.auth.id"
}, collection)
// add field
collection.fields.addAt(3, new Field({
"hidden": false,
"id": "autodate820045582",
"name": "uitgeklokt",
"onCreate": false,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}))
// update field
collection.fields.addAt(2, new Field({
"hidden": false,
"id": "autodate2939903645",
"name": "ingeklokt",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
}))
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_4227797064")
// update collection data
unmarshal({
"createRule": null,
"updateRule": null
}, collection)
// remove field
collection.fields.removeById("autodate820045582")
// update field
collection.fields.addAt(2, new Field({
"hidden": false,
"id": "autodate2939903645",
"name": "datumtijd",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
}))
return app.save(collection)
})
@@ -0,0 +1,20 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_4227797064")
// update collection data
unmarshal({
"listRule": "medewerker.id = @request.auth.id"
}, collection)
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_4227797064")
// update collection data
unmarshal({
"listRule": null
}, collection)
return app.save(collection)
})
@@ -0,0 +1,74 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": "afzender = @request.auth.id",
"deleteRule": null,
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cascadeDelete": false,
"collectionId": "_pb_users_auth_",
"hidden": false,
"id": "relation1489550391",
"maxSelect": 1,
"minSelect": 0,
"name": "afzender",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text2895984270",
"max": 0,
"min": 0,
"name": "bericht",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "autodate1587919980",
"name": "verstuurd",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"id": "pbc_4257786651",
"indexes": [],
"listRule": "",
"name": "berichten",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_4257786651");
return app.delete(collection);
})
@@ -0,0 +1,20 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_4257786651")
// update collection data
unmarshal({
"listRule": "@request.auth.id != ''"
}, collection)
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_4257786651")
// update collection data
unmarshal({
"listRule": ""
}, collection)
return app.save(collection)
})
@@ -0,0 +1,76 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"fields": [
{
"autogeneratePattern": "",
"hidden": false,
"id": "text3208210256",
"max": 0,
"min": 0,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "_clone_7KTY",
"max": 0,
"min": 0,
"name": "bericht",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "_clone_HF2I",
"name": "verstuurd",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "_clone_ItTJ",
"max": 255,
"min": 0,
"name": "naam",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}
],
"id": "pbc_147944274",
"indexes": [],
"listRule": null,
"name": "berichten_bekijken",
"system": false,
"type": "view",
"updateRule": null,
"viewQuery": "SELECT berichten.id, berichten.bericht, berichten.verstuurd, gebruikers.naam FROM berichten\nINNER JOIN gebruikers ON gebruikers.id = berichten.afzender",
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_147944274");
return app.delete(collection);
})
@@ -0,0 +1,126 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_147944274")
// update collection data
unmarshal({
"listRule": ""
}, collection)
// remove field
collection.fields.removeById("_clone_7KTY")
// remove field
collection.fields.removeById("_clone_HF2I")
// remove field
collection.fields.removeById("_clone_ItTJ")
// add field
collection.fields.addAt(1, new Field({
"autogeneratePattern": "",
"hidden": false,
"id": "_clone_oLDn",
"max": 0,
"min": 0,
"name": "bericht",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}))
// add field
collection.fields.addAt(2, new Field({
"hidden": false,
"id": "_clone_bb1h",
"name": "verstuurd",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
}))
// add field
collection.fields.addAt(3, new Field({
"autogeneratePattern": "",
"hidden": false,
"id": "_clone_gXjC",
"max": 255,
"min": 0,
"name": "naam",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}))
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_147944274")
// update collection data
unmarshal({
"listRule": null
}, collection)
// add field
collection.fields.addAt(1, new Field({
"autogeneratePattern": "",
"hidden": false,
"id": "_clone_7KTY",
"max": 0,
"min": 0,
"name": "bericht",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}))
// add field
collection.fields.addAt(2, new Field({
"hidden": false,
"id": "_clone_HF2I",
"name": "verstuurd",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
}))
// add field
collection.fields.addAt(3, new Field({
"autogeneratePattern": "",
"hidden": false,
"id": "_clone_ItTJ",
"max": 255,
"min": 0,
"name": "naam",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
}))
// remove field
collection.fields.removeById("_clone_oLDn")
// remove field
collection.fields.removeById("_clone_bb1h")
// remove field
collection.fields.removeById("_clone_gXjC")
return app.save(collection)
})
+46
View File
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>Chat demo</title>
<!-- Link Pico CSS bestand aan deze pagina -->
<link rel="stylesheet" href="css/vendor/pico.blue.min.css">
<!-- <script defer type="module" src="js/chat.js"></script> -->
<script defer type="module" src="js/chat-onveilig.js"></script>
</head>
<body>
<main class="container">
<nav>
<ul>
<li>
<strong>Demo van Pocketbase</strong>
</li>
</ul>
<ul>
<li>
<a class="outline" role="button" href="index.html">Home</a>
</li>
</ul>
</nav>
<div class="grid">
<article id="berichten">
</article>
<article>
<h2>Bericht versturen</h2>
<form id="verstuurform">
<textarea name="bericht" placeholder="Type je bericht..."></textarea>
<button>Versturen</button>
</form>
</article>
</div>
</main>
</body>
</html>
+3
View File
@@ -0,0 +1,3 @@
.verborgen {
display: none;
}
+4
View File
@@ -0,0 +1,4 @@
@charset "UTF-8";/*!
* Pico CSS ✨ v2.1.1 (https://picocss.com)
* Copyright 2019-2025 - Licensed under MIT
*/:host,:root{--pico-font-family-emoji:"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--pico-font-family-sans-serif:system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif,var(--pico-font-family-emoji);--pico-font-family-monospace:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace,var(--pico-font-family-emoji);--pico-font-family:var(--pico-font-family-sans-serif);--pico-line-height:1.5;--pico-font-weight:400;--pico-font-size:100%;--pico-text-underline-offset:0.1rem;--pico-border-radius:0.25rem;--pico-border-width:0.0625rem;--pico-outline-width:0.125rem;--pico-transition:0.2s ease-in-out;--pico-spacing:1rem;--pico-typography-spacing-vertical:1rem;--pico-block-spacing-vertical:var(--pico-spacing);--pico-block-spacing-horizontal:var(--pico-spacing);--pico-grid-column-gap:var(--pico-spacing);--pico-grid-row-gap:var(--pico-spacing);--pico-form-element-spacing-vertical:0.75rem;--pico-form-element-spacing-horizontal:1rem;--pico-group-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-primary-focus);--pico-group-box-shadow-focus-with-input:0 0 0 0.0625rem var(--pico-form-element-border-color);--pico-modal-overlay-backdrop-filter:blur(0.375rem);--pico-nav-element-spacing-vertical:1rem;--pico-nav-element-spacing-horizontal:0.5rem;--pico-nav-link-spacing-vertical:0.5rem;--pico-nav-link-spacing-horizontal:0.5rem;--pico-nav-breadcrumb-divider:">";--pico-icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pico-icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pico-icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--pico-icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--pico-icon-loading:url("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite; transform-origin: center center; %7D circle %7B stroke-dasharray: 75,100; stroke-dashoffset: -5; animation: dash 1.5s ease-in-out infinite; stroke-linecap: round; %7D @keyframes rotate %7B 0%25 %7B transform: rotate(0deg); %7D 100%25 %7B transform: rotate(360deg); %7D %7D @keyframes dash %7B 0%25 %7B stroke-dasharray: 1,100; stroke-dashoffset: 0; %7D 50%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -17.5; %7D 100%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -62; %7D %7D %3C/style%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='rgb(136, 145, 164)' stroke-width='4' /%3E%3C/g%3E%3C/svg%3E")}@media (min-width:576px){:host,:root{--pico-font-size:106.25%}}@media (min-width:768px){:host,:root{--pico-font-size:112.5%}}@media (min-width:1024px){:host,:root{--pico-font-size:118.75%}}@media (min-width:1280px){:host,:root{--picLine truncated
+41
View File
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PocketDB Demo</title>
<!-- Link Pico CSS bestand aan deze pagina -->
<link rel="stylesheet" href="css/vendor/pico.blue.min.css">
<script defer type="module" src="js/home.js"></script>
</head>
<body>
<main class="container">
<nav>
<ul>
<li>
<strong>Demo van Pocketbase</strong>
</li>
</ul>
<ul>
<li>
<a class="secondary outline" role="button" href="chat.html">Chat</a>
</li>
</ul>
</nav>
<article>
<h1>Welkom, <span id="naam"></span></h1>
<button id="klokknop">Inklokken</button>
<button id="uitlogknop" class="outline">Uitloggen</button>
</article>
</main>
</body>
</html>
+41
View File
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="nl" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>Demo - Inloggen</title>
<!-- Link Pico CSS bestand aan deze pagina -->
<link rel="stylesheet" href="css/vendor/pico.blue.min.css">
<!-- En onze eigen CSS -->
<link rel="stylesheet" href="css/index.css">
<script defer type="module" src="js/inloggen.js"></script>
</head>
<body>
<main class="container">
<article>
<h1>Inloggen</h1>
<form id="loginform">
<fieldset>
<label>
Email
<input type="email" name="email" placeholder="E-mail" />
</label>
<label>
Wachtwoord
<input type="password" name="wachtwoord" placeholder="Wachtwoord" />
<small class="verborgen" id="foutmelding">Gebruikersnaam of wachtwoord onjuist</small>
</label>
</fieldset>
<button>Inloggen</button>
</form>
</article>
</main>
</body>
</html>
+58
View File
@@ -0,0 +1,58 @@
import { database, alleenIngelogd } from "./index.js";
alleenIngelogd();
// Berichten versturen
/** @type {HTMLFormElement} */
const formulier = document.getElementById('verstuurform');
formulier.addEventListener('submit', async (event) => {
event.preventDefault();
const gegevens = new FormData(formulier);
await verstuurBericht(gegevens.get('bericht'))
formulier.reset();
});
async function verstuurBericht(bericht) {
await database.collection('berichten').create({
afzender: database.authStore.record.id,
bericht
});
}
// Laad 20 nieuwste berichten in, soorteer bij verstuurd (hoog naar laag)
const berichten = await database.collection('berichten').getList(1, 20, {
sort: '-verstuurd',
expand: 'afzender'
});
const berichtenlijst = document.getElementById('berichten');
let berichtenHtml = [];
berichten.items.forEach(bericht => {
berichtenHtml.push(`<article>
<h3>${bericht.expand.afzender.naam}</h3>
<p>${bericht.verstuurd}</p>
<h5>${bericht.bericht}</h5>
</article>`);
});
berichtenlijst.innerHTML = berichtenHtml.join('\n');
// Schrijf in op nieuwe berichten (Create) en werk dan de berichtenlijst bij
database.collection('berichten').subscribe('*', function(event) {
if(event.action !== 'create') {
return;
}
const bericht = event.record;
berichtenlijst.innerHTML = `<article>
<h3>${bericht.expand.afzender.naam}</h3>
<p>${bericht.verstuurd}</p>
<h5>${bericht.bericht}</h5>
</article>` + '\n' + berichtenlijst.innerHTML;
}, {
expand: 'afzender'
});
+54
View File
@@ -0,0 +1,54 @@
import { database, alleenIngelogd } from "./index.js";
alleenIngelogd();
// Berichten versturen
/** @type {HTMLFormElement} */
const formulier = document.getElementById('verstuurform');
formulier.addEventListener('submit', async (event) => {
event.preventDefault();
const gegevens = new FormData(formulier);
await verstuurBericht(gegevens.get('bericht'))
formulier.reset();
});
async function verstuurBericht(bericht) {
await database.collection('berichten').create({
afzender: database.authStore.record.id,
bericht
});
}
// Laad 20 nieuwste berichten in, soorteer bij verstuurd (hoog naar laag)
const berichten = await database.collection('berichten_bekijken').getList(1, 20, {
sort: '-verstuurd'
});
const berichtenlijst = document.getElementById('berichten');
let berichtenHtml = [];
berichten.items.forEach(bericht => {
berichtenHtml.push(`<article>
<h3>${bericht.naam}</h3>
<p>${bericht.verstuurd}</p>
<h5>${bericht.bericht}</h5>
</article>`);
});
berichtenlijst.innerHTML = berichtenHtml.join('\n');
// Schrijf in op nieuwe berichten (Create) en werk dan de berichtenlijst bij
// Helaas kan dit niet, subscriben op een view...
database.collection('berichten_bekijken').subscribe('*', function(event) {
const bericht = event.record;
berichtenlijst.innerHTML = `<article>
<h3>${bericht.naam}</h3>
<p>${bericht.verstuurd}</p>
<h5>${bericht.bericht}</h5>
</article>` + '\n' + berichtenlijst.innerHTML;
}, {
expand: 'afzender'
});
+52
View File
@@ -0,0 +1,52 @@
import { alleenIngelogd, database } from "./index.js";
// Controleer of iemand ingelogd is
alleenIngelogd();
// Toon naam van ingelogde gebruiker
document.getElementById('naam').textContent =
database.authStore.record.naam;
// Haal eerste record is waarop gebruiker NIET uitgeklokt is (dan is iemand namelijk ingeklokt)
let ingeklokt = undefined;
try {
const item = await database.collection('klokken').getFirstListItem('uitgeklokt = NULL');
ingeklokt = item.id;
document.getElementById('klokknop').textContent = 'Uitklokken';
} catch {
// Niet ingeklokt, want niet gevonden
}
document.getElementById('klokknop').addEventListener('click', async () => {
try {
if (!ingeklokt) {
await inklokken();
} else {
await uitklokken();
}
} catch {
alert('In- of uitklokken mislukt');
}
});
document.getElementById('uitlogknop').addEventListener('click', () => {
database.authStore.clear();
window.location.href = 'inloggen.html';
});
async function inklokken() {
const item = await database.collection('klokken')
.create({ medewerker: database.authStore.record.id });
document.getElementById('klokknop').textContent = 'Uitklokken';
ingeklokt = item.id;
}
async function uitklokken() {
await database.collection('klokken')
.update(ingeklokt);
document.getElementById('klokknop').textContent = 'Inklokken';
ingeklokt = undefined;
}
+18
View File
@@ -0,0 +1,18 @@
import PocketBase from './vendor/pocketbase.es.js';
/**
* Database
*/
export const database = new PocketBase('http://localhost:8090');
window.db = database;
/**
* Controleer of iemand ingelogd is. Zo niet, stuur iemand naar inloggen.html
*/
export function alleenIngelogd() {
// Als iemand niet ingelogd is, stuur iemand naar inloggen.js
if (!database.authStore.isValid) {
window.location.href = 'inloggen.html';
}
}
+45
View File
@@ -0,0 +1,45 @@
import { ClientResponseError } from './vendor/pocketbase.es.js';
import { database } from './index.js';
/** @type {HTMLFormElement} */
const inlogformulier = document.getElementById('loginform');
inlogformulier.addEventListener('submit', async (event) => {
event.preventDefault(); // Voorkomt dat de pagina gaat herladen
const formdata = new FormData(inlogformulier);
try {
const email = formdata.get('email');
const wachtwoord = formdata.get('wachtwoord');
await database.collection('gebruikers').authWithPassword(email, wachtwoord);
verbergFoutmeldingen();
// Inloggen gelukt, ga naar andere pagina
window.location.href = 'index.html';
} catch (e) {
/** @type {ClientResponseError} */
const error = e;
if (error.status === 400) {
toonFoutmeldingen();
}
}
});
function toonFoutmeldingen() {
// Toon foutmelding
document.getElementById('foutmelding').classList.remove('verborgen');
// Maak wachtwoord, email rood
Array.from(document.getElementsByTagName('input'))
.forEach(veld => veld.ariaInvalid = true);
}
function verbergFoutmeldingen() {
document.getElementById('foutmelding').classList.add('verborgen');
Array.from(document.getElementsByTagName('input'))
.forEach(veld => veld.ariaInvalid = undefined);
}
+1583
View File
File diff suppressed because it is too large. Load diff
+2
View File
@@ -0,0 +1,2 @@
class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&("AbortError"==e.name||20==e.code)&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong."),this.cause=this.originalError}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n<e.length;){const t=e.indexOf("=",n);if(-1===t)break;let r=e.indexOf(";",n);if(-1===r)r=e.length;else if(r<t){n=e.lastIndexOf(";",t-1)+1;continue}const o=e.slice(n,t).trim();if(void 0===s[o]){let n=e.slice(t+1,r).trim();34===n.charCodeAt(0)&&(n=n.slice(1,-1));try{s[o]=i(n)}catch(e){s[o]=n}}n=r+1}return s}function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStorLine truncated
//# sourceMappingURL=pocketbase.es.js.map