diff --git a/web-app/src/app.html b/web-app/src/app.html
index 84ffad1..66aee01 100644
--- a/web-app/src/app.html
+++ b/web-app/src/app.html
@@ -4,6 +4,7 @@
+
%sveltekit.head%
diff --git a/web-app/src/lib/components/WebsiteEditor.svelte b/web-app/src/lib/components/WebsiteEditor.svelte
new file mode 100644
index 0000000..c767c95
--- /dev/null
+++ b/web-app/src/lib/components/WebsiteEditor.svelte
@@ -0,0 +1,45 @@
+
+
+
+
{title}
+
+
+
+ {@render children()}
+
+
+
+ {@html previewContent}
+
+
+
diff --git a/web-app/src/lib/server/utils.ts b/web-app/src/lib/server/utils.ts
new file mode 100644
index 0000000..958b727
--- /dev/null
+++ b/web-app/src/lib/server/utils.ts
@@ -0,0 +1,66 @@
+import { randomUUID } from "node:crypto";
+import { mkdir, writeFile } from "node:fs/promises";
+import { extname, join, relative } from "node:path";
+import { ALLOWED_MIME_TYPES } from "../utils";
+
+export const handleFileUpload = async (
+ file: File,
+ contentId: string,
+ userId: string,
+ session_token: string | undefined,
+ customFetch: typeof fetch
+) => {
+ if (file.size === 0) return undefined;
+
+ const MAX_FILE_SIZE = 1024 * 1024;
+
+ if (file.size > MAX_FILE_SIZE) {
+ return {
+ success: false,
+ message: `File size exceeds the maximum limit of ${MAX_FILE_SIZE / 1024 / 1024} MB.`
+ };
+ }
+
+ if (!ALLOWED_MIME_TYPES.includes(file.type)) {
+ return {
+ success: false,
+ message: "Invalid file type. JPEG, PNG, SVG and WEBP are allowed."
+ };
+ }
+
+ const buffer = Buffer.from(await file.arrayBuffer());
+ const uploadDir = join(process.cwd(), "static", "user-uploads", userId);
+ await mkdir(uploadDir, { recursive: true });
+
+ const fileId = randomUUID();
+ const fileExtension = extname(file.name);
+ const filepath = join(uploadDir, `${fileId}${fileExtension}`);
+
+ await writeFile(filepath, buffer);
+
+ const relativePath = relative(join(process.cwd(), "static"), filepath);
+
+ const res = await customFetch("http://localhost:3000/media", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${session_token}`,
+ Prefer: "return=representation",
+ Accept: "application/vnd.pgrst.object+json"
+ },
+ body: JSON.stringify({
+ website_id: contentId,
+ user_id: userId,
+ original_name: file.name,
+ file_system_path: relativePath
+ })
+ });
+
+ const response = await res.json();
+
+ if (!res.ok) {
+ return { success: false, message: response.message };
+ }
+
+ return { success: true, content: response.id };
+};
diff --git a/web-app/src/routes/(anonymous)/login/+page.server.ts b/web-app/src/routes/(anonymous)/login/+page.server.ts
index bcab662..2b58918 100644
--- a/web-app/src/routes/(anonymous)/login/+page.server.ts
+++ b/web-app/src/routes/(anonymous)/login/+page.server.ts
@@ -18,6 +18,6 @@ export const actions = {
}
cookies.set("session_token", response.token, { path: "/" });
- return { success: true };
+ return { success: true, message: "Successfully logged in" };
}
};
diff --git a/web-app/src/routes/(anonymous)/login/+page.svelte b/web-app/src/routes/(anonymous)/login/+page.svelte
index f086a8b..0ba5c3a 100644
--- a/web-app/src/routes/(anonymous)/login/+page.svelte
+++ b/web-app/src/routes/(anonymous)/login/+page.svelte
@@ -4,21 +4,21 @@
const { form } = $props();
+{#if form?.success}
+ {form.message}
+{/if}
+
+{#if form?.success === false}
+ {form.message}
+{/if}
+
+
+
+ {/each}
+
+{/if}
diff --git a/web-app/src/routes/(authenticated)/account/+page.server.ts b/web-app/src/routes/(authenticated)/account/+page.server.ts
index 75b6153..2ac86a7 100644
--- a/web-app/src/routes/(authenticated)/account/+page.server.ts
+++ b/web-app/src/routes/(authenticated)/account/+page.server.ts
@@ -8,7 +8,7 @@ export const actions = {
logout: async ({ cookies }) => {
cookies.delete("session_token", { path: "/" });
- return { logout: { success: true } };
+ return { success: true, message: "Successfully logged out" };
},
deleteAccount: async ({ request, fetch, cookies }) => {
const data = await request.formData();
@@ -27,10 +27,10 @@ export const actions = {
const response = await res.json();
if (!res.ok) {
- return { deleteAccount: { success: false, message: response.message } };
+ return { success: false, message: response.message };
}
cookies.delete("session_token", { path: "/" });
- return { deleteAccount: { success: true } };
+ return { success: true, message: "Successfully deleted account" };
}
};
diff --git a/web-app/src/routes/(authenticated)/account/+page.svelte b/web-app/src/routes/(authenticated)/account/+page.svelte
index 8efddd9..b10ee3e 100644
--- a/web-app/src/routes/(authenticated)/account/+page.svelte
+++ b/web-app/src/routes/(authenticated)/account/+page.svelte
@@ -4,6 +4,14 @@
const { data, form } = $props();
+{#if form?.success}
+ {form.message}
+{/if}
+
+{#if form?.success === false}
+ {form.message}
+{/if}
+
Overview
@@ -20,10 +28,6 @@
Logout
- {#if form?.logout?.success}
- Successfully logged out
- {/if}
-
@@ -32,17 +36,9 @@
Delete account
- {#if form?.deleteAccount?.success}
- Account was deleted
- {/if}
-
- {#if form?.deleteAccount?.success === false}
- {form.deleteAccount.message}
- {/if}
-