Configure API to send website updates on change

This commit is contained in:
Manuel Bustillo 2025-06-08 20:46:10 +02:00
parent 97d47b339a
commit 847666bfc8
4 changed files with 60 additions and 6 deletions

View File

@ -2,15 +2,34 @@
'use client'
import Tiptap from '../../../components/Tiptap'
import { AbstractApi } from '@/app/api/abstract-api';
import { Website, WebsiteSerializer } from '@/app/lib/website';
import { useEffect, useState } from 'react';
import Tiptap from '../../../components/Tiptap';
export default function Page() {
const [website, setWebsite] = useState<Website>()
const api = new AbstractApi<Website>();
const serializer = new WebsiteSerializer();
useEffect(() => {
api.get(serializer, undefined, (loadedWebsite) => {
setWebsite(loadedWebsite);
console.log('Website loaded:', loadedWebsite);
});
}, []);
const updateWebsite = (newContent: string) => {
api.update(serializer, new Website('', newContent), () => { });
}
return (
<div className="border rounded-lg p-4">
<Tiptap
content="<p>Hello World! 🌎️</p>"
onUpdate={(newContent) => console.log(newContent)}
key={website?.content ?? 'empty'}
content={website?.content || ''}
onUpdate={updateWebsite}
/>
</div>
);

View File

@ -6,6 +6,7 @@ import { getCsrfToken, getSlug } from '@/app/lib/utils';
export interface Api<T extends Entity> {
getAll(serializable: Serializable<T>, callback: (objets: T[]) => void): void;
get(serializable: Serializable<T>, id: string, callback: (object: T) => void): void;
getSingleton(serializable: Serializable<T>, callback: (object: T) => void): void;
create(serializable: Serializable<T>, object: T, callback: (object: T) => void): void;
update(serializable: Serializable<T>, object: T, callback: () => void): void;
destroy(serializable: Serializable<T>, object: T, callback: () => void): void;
@ -30,8 +31,9 @@ export class AbstractApi<T extends Entity> implements Api<T> {
});
}
get(serializable: Serializable<T>, id: string, callback: (object: T) => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}/${id}`)
get(serializable: Serializable<T>, id: (string | undefined), callback: (object: T) => void): void {
const endpoint = id ? `/api/${getSlug()}/${serializable.apiPath()}/${id}` : `/api/${getSlug()}/${serializable.apiPath()}`;
fetch(endpoint)
.then((response) => response.json())
.then((data) => {
callback(serializable.fromJson(data));
@ -41,7 +43,9 @@ export class AbstractApi<T extends Entity> implements Api<T> {
}
update(serializable: Serializable<T>, object: T, callback: () => void): void {
fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, {
const endpoint = object.id ? `/api/${getSlug()}/${serializable.apiPath()}/${object.id}` : `/api/${getSlug()}/${serializable.apiPath()}`;
fetch(endpoint, {
method: 'PUT',
body: serializable.toJson(object),
headers: {

View File

@ -13,6 +13,7 @@ const Tiptap = ({ content, onUpdate }: { content: string, onUpdate: (newContent:
onUpdate({ editor }) {
onUpdate(editor.getHTML());
},
immediatelyRender: false,
})
return <EditorContent editor={editor} />

30
app/lib/website.tsx Normal file
View File

@ -0,0 +1,30 @@
/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/
import { Serializable } from "../api/abstract-api";
import { Entity } from "./definitions";
export class Website implements Entity {
id?: string;
content?: string;
constructor(id: string, content: string) {
this.id = id;
this.content = content;
}
}
export class WebsiteSerializer implements Serializable<Website> {
fromJson(data: any): Website {
return new Website("", data.content);
}
toJson(website: Website): string {
return JSON.stringify({ website: { content: website.content } });
}
apiPath(): string {
return 'website';
}
}