Skip to main content
  1. Blog/

Soccer App - Recap Step 2: Sveltekit/Pocketbase Authentication CSR SSR

·869 words·5 mins
Author
Kees Fluitman
I am a pedagog, hobbyist, allrounder and self-taught beginning software engineer. I am also a privacy advocate and enjoy privacy enhancing technologies.
Table of Contents

In continuation of my first Svelte Post, I’ve changed my database Schema and going forth, I decided to work with template spatz-2. I’ve updated several dependencies, installed the newest shadcn-svelte components and the template still works great. A template allows me to learn from existing code, yet skip unnecessary frontend development and other crucial yet repetitive tasks. There is still plenty of work to do, but gradually, Im becoming more proficient with JS, TS and Sveltekit syntax. My latest updates are:

  • Schema Changes in Pocketbase
  • Usage of updated and customized Spatz-2 template
  • Basic Calendar overview

Schema Changes
#

I’ve made the decision to extend my Schema, this way, more features are more easily incorporated at a later stage. Like Live Tournaments, Multiple Clubs and much more.

erDiagram users { string name string email select role } players { string first_name string last_name date birthday } teams { string category string team } clubs { string name string location date founded } users ||--o{ players : guardians users ||--o{ teams : trainers players ||--o{ teams : belongs_to clubs ||--o{ teams : has

erDiagram events { date date string organizer string location } teams { string category string team } players { string first_name string last_name date birthday } clubs { string name string location date founded } events ||--o{ teams : "participates" events ||--o{ players : "participates" events ||--o{ clubs : "participates"

Or see the more expansive UML Schema of my database.

First Review of Database Schema

First Review of Database Schema

Basic Calendar overview
#

The calendar will be the backbone and most important. It should hold:

  • Quick Overview
  • Sign up of Players
  • Visual pleasing Accordion with more info
  • Filters to filter on: Team/Player, EventType
  • Search
  • Load More button / Progressive loading
First Review of Database Schema

Spatz-2
#

Spatz-2 uses Shadcn-svelte components, zod and superforms (but not everything from superforms) and gsap for animations.

Components
#

A component like a back button is defined like this. I give it props like onclick, size, variant, extra classes and an Icon. The Icon is also a component which makes it easier to add SVG icons, without having my code become unreadable and get cluttered with SVG code.

<Button
    onclick={() => window.history.back()}
    size="sm"
    variant="outline"
    class="group/backButton backButton flex items-center gap-2">
    <Icon
        icon="mdi:arrow-left"
        class="h-5 w-5 transition-all duration-300 md:group-hover/backButton:-translate-x-1"
    />
    <span class="text-sm">back</span>
</Button>

Gsap
#

Gsap is a complex, comprehensive library to create smooth and modern looking animations. Makes everything look all the more professional, without having to understand all the ins and outs of CSS and get lost in Frontend Development.

Gsap in animations.ts file.

import { gsap } from 'gsap';

export const animateMainStagger = () => {
	gsap.from('.animate-item', {
		opacity: 0,
		y: 20,
		duration: 1,
		delay: 0.1,
		stagger: 0.1,
		ease: 'power4.out'
	});
};

the onMount executes the exported animateMainStagger function. Gsap takes over.

	onMount(() => {
		animateMainStagger();
	});

Typescript
#

As an example for my problems with Typescript, I provide an example here.

	import type {
		EventsRecord,
		UsersRecord,
		TeamsRecord,
		ClubsRecord
	} from '$lib/types/pocketbase-types';

	type ExpandedEvent = EventsRecord & {
		expand: {
			players: Array<UsersRecord>;
			teams: Array<TeamsRecord>;
			clubs: Array<ClubsRecord>;
		};
	};

	interface Props {
		data?: {
			events?: Array<ExpandedEvent>;
		};
	}

	let { data }: Props = $props();

	// Ensure events is always an array
	let events: ExpandedEvent[] = $derived(data?.events ?? []);

	function getEventsByMonth(events: Array<ExpandedEvent>): Record<string, Array<ExpandedEvent>> {
		const grouped: Record<string, Array<ExpandedEvent>> = {};
		const sortedEvents = [...events].sort(
			(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
		);

		sortedEvents.forEach((event) => {
			const date = new Date(event.date);
			const monthYear = date.toLocaleString('default', { month: 'long', year: 'numeric' });

			if (!grouped[monthYear]) {
				grouped[monthYear] = [];
			}
			grouped[monthYear].push(event);
		});

		return grouped;
	}

This Code imports the Pocketbase Types from my pocketbase-types.ts file. Basically a Schema of an Event it’s properties (aka variables). For example for Teams:

export type TeamsRecord = {
	category?: string
	created?: IsoDateString
	id: string
	players?: RecordIdString[]
	team?: string
	trainers?: RecordIdString[]
	updated?: IsoDateString
}

The same code in Javascript would be:

let { data } = $props();
let events = $derived(data.events ?? []);

function getEventsByMonth(events) {
	const grouped = {};
	const sortedEvents = [...events].sort(
		(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
	);

	sortedEvents.forEach((event) => {
		const date = new Date(event.date);
		const monthYear = date.toLocaleString('default', { month: 'long', year: 'numeric' });

		if (!grouped[monthYear]) {
			grouped[monthYear] = [];
		}
		grouped[monthYear].push(event);
	});

	return grouped;
}

So there is a clear difference. For getting more IDE support and better maintainability, we have to sacrifice concise Syntax. The code with all it’s :: <> and {} becomes quite confusing at times.

Goals
#

There is a lot to do. I want to especially focus on a deep understanding of the workings of Sveltekit, Javascript and Typescript. Especially the Types sometimes confuse me. The syntax makes the code harder to read, and my codebase is not yet that complicated, that it has really benefited me. Rather only confused me more. My general goals are:

  • Improve my Typescript understanding
  • Sveltekit understanding
  • Write more code myself instead of Claude’s LLM

My next steps are:

  • Implement a Current Player (in case of Users that have multiple Children or Trainers that should be able to change multiple players)
  • Create the filters of the Calendar
  • Signup button (is still only visually)
  • More comprehensive Pocketbase API Authorization of individual Tables (Still open to anyone)