feat: rewrite /about and /book with tested booking URL parsing

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 19:20:40 +02:00
co-authored by Claude Sonnet 5.5
parent a9702dc3ff
commit cc0d9bd9c2
10 changed files with 349 additions and 248 deletions
+22
View File
@@ -0,0 +1,22 @@
import * as React from "react";
type TagListProps = {
readonly title: string;
readonly items: readonly string[];
};
export const TagList: React.FC<TagListProps> = ({ title, items }) => (
<div>
<h2 className="!mb-3 !mt-0 !text-xl">{title}</h2>
<ul className="!m-0 flex !list-none flex-wrap gap-2 !p-0">
{items.map((item) => (
<li
key={item}
className="rounded-md border border-border-strong px-3 py-1 font-mono text-sm text-fg"
>
{item}
</li>
))}
</ul>
</div>
);
@@ -0,0 +1,23 @@
import * as React from "react";
import type { TimelineEntry } from "./aboutData";
type TimelineProps = { readonly entries: readonly TimelineEntry[] };
export const Timeline: React.FC<TimelineProps> = ({ entries }) => (
<ol className="!m-0 !list-none divide-y divide-border border-y border-border !p-0">
{entries.map((entry) => (
<li
key={`${entry.period}-${entry.company}`}
className="grid gap-1 py-3 sm:grid-cols-[9rem_1fr]"
>
<span className="font-mono text-sm text-accent">{entry.period}</span>
<span className="text-fg">
{entry.role}, {entry.company}
{entry.note ? (
<span className="text-muted"> ({entry.note})</span>
) : null}
</span>
</li>
))}
</ol>
);
@@ -0,0 +1,53 @@
export type TimelineEntry = {
readonly period: string;
readonly role: string;
readonly company: string;
readonly note?: string;
};
export const TIMELINE: readonly TimelineEntry[] = [
{ period: "2011-2014", role: "Apprenticeship", company: "webfactory.de" },
{ period: "2014-2016", role: "Frontend developer", company: "gct" },
{
period: "2016-2020",
role: "Frontend developer to frontend team lead",
company: "i22 Digitalagentur",
},
{ period: "2020-2021", role: "Senior developer", company: "Trusted Shops" },
{
period: "2021-2023",
role: "Senior developer",
company: "sdox.io",
note: "remote",
},
{
period: "2024-now",
role: "Founder",
company: "Cable Creations",
note: "own product business",
},
];
export const STACK_ITEMS: readonly string[] = [
"TypeScript",
"Next.js / React",
"Tailwind",
"Node",
"Rust",
"Solidity",
"Postgres basics",
"Docker",
];
export const NOT_MY_THING: readonly string[] = [
"Windows apps",
"Mobile apps",
"Running client infrastructure",
"Database tuning",
];
export const WORKING_MODE: readonly string[] = [
"Async-first and fully remote, with overlap hours in the DACH time zone.",
"Transparent time tracking and a weekly delivery report.",
"Simple SOW and a 2-week notice period.",
];
@@ -0,0 +1,29 @@
"use client";
import * as React from "react";
import {
formatAvailability,
resolveAvailability,
} from "@/src/domain/availability";
import { AVAILABILITY_CONFIG } from "@/src/content/site";
const toIsoDate = (date: Date): string => {
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${date.getFullYear()}-${month}-${day}`;
};
export const AvailabilityLine: React.FC = () => {
const [text, setText] = React.useState<string | null>(null);
React.useEffect(() => {
setText(
formatAvailability(
resolveAvailability(AVAILABILITY_CONFIG, toIsoDate(new Date())),
),
);
}, []);
if (text === null) return null;
return <p className="font-mono text-sm text-accent">{text}</p>;
};
@@ -0,0 +1,46 @@
import * as React from "react";
import { parseBookingUrl } from "@/src/domain/booking";
import { BOOKING_URL, CONTACT_EMAIL } from "@/src/content/site";
export const BookingEmbed: React.FC = () => {
const parsed = parseBookingUrl(BOOKING_URL);
if (parsed.ok === false) {
return (
<div
role="status"
className="rounded-md border border-border-strong p-5 text-sm"
>
<p className="!mb-2 font-semibold text-fg">
Booking link not configured
</p>
<p className="!mb-0 text-muted">
The calendar is not available yet. Please email{" "}
<a href={`mailto:${CONTACT_EMAIL}`}>{CONTACT_EMAIL}</a> to arrange a
call.
</p>
</div>
);
}
const { href } = parsed.value;
return (
<div>
<iframe
src={href}
title="Book a 20-minute intro call"
loading="lazy"
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
className="w-full rounded-md border-0"
style={{ minHeight: 700 }}
/>
<p className="mt-3 text-sm text-muted">
Embed not loading?{" "}
<a href={href} target="_blank" rel="noopener noreferrer">
Open the booking page directly
</a>
.
</p>
</div>
);
};
+55
View File
@@ -0,0 +1,55 @@
import { describe, expect, it } from "vitest";
import { parseBookingUrl } from "./booking";
describe("parseBookingUrl", () => {
it("accepts an https URL and returns it normalized", () => {
expect(parseBookingUrl("https://cal.com/marc/intro")).toEqual({
ok: true,
value: { href: "https://cal.com/marc/intro" },
});
});
it("rejects http", () => {
expect(parseBookingUrl("http://cal.com/marc/intro")).toEqual({
ok: false,
error: "not-https",
});
});
it("rejects other protocols", () => {
expect(parseBookingUrl("javascript:alert(1)")).toEqual({
ok: false,
error: "not-https",
});
});
it("rejects garbage as invalid", () => {
expect(parseBookingUrl("not a url")).toEqual({
ok: false,
error: "invalid-url",
});
});
it("rejects an empty string", () => {
expect(parseBookingUrl("")).toEqual({ ok: false, error: "empty" });
expect(parseBookingUrl(" ")).toEqual({ ok: false, error: "empty" });
});
it("rejects a placeholder URL regardless of case", () => {
expect(parseBookingUrl("https://cal.com/PLACEHOLDER/intro")).toEqual({
ok: false,
error: "placeholder",
});
expect(parseBookingUrl("https://cal.com/placeholder/intro")).toEqual({
ok: false,
error: "placeholder",
});
});
it("trims surrounding whitespace", () => {
expect(parseBookingUrl(" https://cal.com/marc/intro ")).toEqual({
ok: true,
value: { href: "https://cal.com/marc/intro" },
});
});
});
+25
View File
@@ -0,0 +1,25 @@
import type { Result } from "./availability";
export type BookingUrl = { readonly href: string };
export type BookingUrlError =
| "empty"
| "invalid-url"
| "not-https"
| "placeholder";
const PLACEHOLDER_MARKER = "placeholder";
export function parseBookingUrl(
raw: string,
): Result<BookingUrl, BookingUrlError> {
const trimmed = raw.trim();
if (trimmed === "") return { ok: false, error: "empty" };
if (!URL.canParse(trimmed)) return { ok: false, error: "invalid-url" };
const url = new URL(trimmed);
if (url.protocol !== "https:") return { ok: false, error: "not-https" };
if (url.href.toLowerCase().includes(PLACEHOLDER_MARKER)) {
return { ok: false, error: "placeholder" };
}
return { ok: true, value: { href: url.href } };
}