mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 00:01:10 +02:00
Wires Calendar through the M8.1+M8.2 backbone: flipping an event to
'unlisted' now publishes a server-side snapshot, the visible link in
the DetailView/EventDetailModal opens a real /share/[token] page, and
recipients can download an .ics file for their own calendar.
Changes:
- lib/data/unlisted/resolvers.ts (new):
buildUnlistedBlob(collection, recordId) dispatcher.
buildEventBlob: load LocalEvent + linked TimeBlock, decrypt
client-side, return { title, location, startTime, endTime,
isAllDay, timezone }. Description, reminders, tagIds, calendarId,
color stay out of the blob — sensitive context the user didn't
consent to share by flipping a single flag.
- modules/calendar/types: CalendarEvent gains `unlistedToken: string`
(empty string when no active token). timeBlockToCalendarEvent
forwards from LocalEvent. Draft-event scaffold initializes empty.
- modules/calendar/stores/events:
setVisibility now coordinates with mana-api. Flip-to-unlisted:
build blob -> publishUnlistedSnapshot -> store server-issued
token in patch.unlistedToken -> commit local update. If the
server call fails, no local change happens (no drift).
Flip-from-unlisted: revoke server snapshot first, then clear
local token + commit visibility change.
deleteEvent: revoke active unlisted snapshot before tombstoning,
so the share-link dies in lock-step with the local delete.
updateEvent + updateSingleInstance fire-and-forget
refreshUnlistedSnapshot(id) so the published blob tracks any
whitelist-field edits. Failures log; the next successful
refresh heals.
New regenerateUnlistedToken(id): revoke + republish in one call,
returns the fresh token. Powers the "Neu erzeugen" UI.
- routes/share/[token]/+layout.svelte: minimal anonymous chrome —
no app nav, no auth, no Dexie. Light/dark via prefers-color-scheme.
Footer carries "Geteilt via Mana" + signup CTA.
- routes/share/[token]/+page.server.ts: SSR loader. Fetches
/api/v1/unlisted/public/:token, dispatches 404/410 cleanly,
sets Cache-Control: private, max-age=60 + X-Robots-Tag: noindex.
- routes/share/[token]/+page.svelte: dispatcher; renders
SharedEventView for collection='events', stub message otherwise.
- modules/calendar/SharedEventView.svelte: standalone public render —
big date, location, "Zum eigenen Kalender hinzufügen" .ics link,
optional expiry note. OG/Twitter meta tags for WhatsApp/Slack
preview embedding. Uses $derived everywhere so prop updates
propagate through reactive recompute.
- routes/share/[token]/ical/+server.ts: RFC 5545 builder. No npm
library — small enough to inline. Escapes per spec, CRLF endings,
DTSTART/DTEND swap between VALUE=DATE and UTC depending on isAllDay.
Wrong-collection requests get 400.
- modules/calendar/views/DetailView (Workbench) + components/
EventDetailModal (/calendar route): SharedLinkControls dropped in
below the visibility row when event.visibility === 'unlisted'
AND event.unlistedToken AND shareUrl computed. The URL is built
client-side via buildShareUrl(window.location.origin, token) so it
stays in sync with whichever host the editor is open on.
Verified:
- pnpm check (web): 7541 files, 0 errors, 0 warnings
- pnpm test calendar + website: 26/26
- typecheck of new resolver, store hooks, SSR loader, iCal builder
Manual test path:
1. Open /calendar event in Detail view, flip Sichtbarkeit -> "Per Link"
2. Server publishes snapshot, Dexie record gets the server token
3. SharedLinkControls appear with copy + regenerate + revoke buttons
4. Open the URL in incognito → SSR fetches snapshot, renders
SharedEventView with date / location / .ics download
5. Edit the event title back in the main app → snapshot auto-refreshes
(refreshUnlistedSnapshot fires after updateEvent succeeds)
6. Flip back to "Bereich" → snapshot revoked server-side; subsequent
incognito reloads return 410 Gone
Next: M8.4 — same wiring for Library + Places. Uses the same
infra (resolvers dispatcher, share dispatcher) — just adds two new
buildXBlob functions, two SharedXView components, and the store
hooks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
2.6 KiB
JSON
37 lines
2.6 KiB
JSON
{
|
|
"apps/mana/apps/web/src/lib/components/dashboard/widgets/TasksTodayWidget.svelte": 1,
|
|
"apps/mana/apps/web/src/lib/components/dashboard/widgets/TransactionsWidget.svelte": 1,
|
|
"apps/mana/apps/web/src/lib/components/OfflineIndicator.svelte": 3,
|
|
"apps/mana/apps/web/src/lib/components/PwaUpdatePrompt.svelte": 3,
|
|
"apps/mana/apps/web/src/lib/modules/period/ListView.svelte": 1,
|
|
"apps/mana/apps/web/src/lib/modules/plants/ListView.svelte": 5,
|
|
"apps/mana/apps/web/src/lib/modules/quotes/components/QuoteCard.svelte": 4,
|
|
"apps/mana/apps/web/src/lib/modules/times/components/EntryForm.svelte": 6,
|
|
"apps/mana/apps/web/src/lib/modules/times/components/EntryItem.svelte": 6,
|
|
"apps/mana/apps/web/src/lib/modules/times/components/EntryList.svelte": 2,
|
|
"apps/mana/apps/web/src/lib/modules/times/components/TimerCard.svelte": 6,
|
|
"apps/mana/apps/web/src/lib/modules/times/components/TimerIndicator.svelte": 2,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/+page.svelte": 10,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/add-city/+page.svelte": 21,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/cities/[slug]/+page.svelte": 10,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/cities/[slug]/add/+page.svelte": 27,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/cities/[slug]/locations/[id]/+page.svelte": 22,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/cities/[slug]/locations/[id]/edit/+page.svelte": 26,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/cities/[slug]/map/+page.svelte": 6,
|
|
"apps/mana/apps/web/src/routes/(app)/citycorners/favorites/+page.svelte": 6,
|
|
"apps/mana/apps/web/src/routes/(app)/quotes/+page.svelte": 3,
|
|
"apps/mana/apps/web/src/routes/(app)/quotes/categories/+page.svelte": 2,
|
|
"apps/mana/apps/web/src/routes/(app)/quotes/category/[category]/+page.svelte": 8,
|
|
"apps/mana/apps/web/src/routes/(app)/quotes/favorites/+page.svelte": 8,
|
|
"apps/mana/apps/web/src/routes/(app)/quotes/lists/[id]/+page.svelte": 31,
|
|
"apps/mana/apps/web/src/routes/(app)/quotes/lists/+page.svelte": 16,
|
|
"apps/mana/apps/web/src/routes/(app)/times/+page.svelte": 4,
|
|
"apps/mana/apps/web/src/routes/(app)/times/clients/[id]/+page.svelte": 6,
|
|
"apps/mana/apps/web/src/routes/(app)/times/clients/+page.svelte": 12,
|
|
"apps/mana/apps/web/src/routes/(app)/times/clock/alarms/+page.svelte": 8,
|
|
"apps/mana/apps/web/src/routes/(app)/times/entries/+page.svelte": 6,
|
|
"apps/mana/apps/web/src/routes/(app)/times/projects/[id]/+page.svelte": 12,
|
|
"apps/mana/apps/web/src/routes/(app)/times/projects/+page.svelte": 11,
|
|
"apps/mana/apps/web/src/routes/(app)/times/reports/+page.svelte": 12,
|
|
"apps/mana/apps/web/src/routes/(app)/times/templates/+page.svelte": 8
|
|
}
|