diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 9f62858..e489d64 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -1,4 +1,5 @@ -// api.ts +import type { Form, Submission, LoginCredentials } from './types'; + const API_BASE_URL = 'http://127.0.0.1:8080'; /** @@ -27,7 +28,7 @@ export async function createForm(name: string, fields: unknown): Promise * Get all forms. * @returns An array of forms. */ -export async function getForms(): Promise { +export async function getForms(): Promise { const response = await fetch(`${API_BASE_URL}/forms`, { method: 'GET', headers: { @@ -69,7 +70,7 @@ export async function submitForm(formId: string, data: unknown): Promise * @param formId The ID of the form. * @returns An array of submissions for the form. */ -export async function getSubmissions(formId: string): Promise { +export async function getSubmissions(formId: string): Promise { const response = await fetch(`${API_BASE_URL}/forms/${formId}/submissions`, { method: 'GET', headers: { @@ -83,3 +84,47 @@ export async function getSubmissions(formId: string): Promise { return await response.json(); } + +/** + * Admin login to get a token. + * @param credentials The login credentials (username and password). + * @returns The generated JWT token if successful. + */ +export async function adminLogin(credentials: LoginCredentials): Promise { + const response = await fetch(`${API_BASE_URL}/admin/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(credentials) + }); + + if (!response.ok) { + throw new Error(`Error during admin login: ${response.statusText}`); + } + + const data = await response.json(); + return data.token; // Assuming the response contains the token +} + +/** + * Create a new admin user. + * @param user The login credentials for the admin user. + * @returns A success message upon creation. + */ +export async function createAdmin(user: LoginCredentials): Promise { + const response = await fetch(`${API_BASE_URL}/admin/create`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(user) + }); + + if (!response.ok) { + throw new Error(`Error creating admin user: ${response.statusText}`); + } + + const data = await response.json(); + return data.message; // Assuming the response contains a success message +} diff --git a/frontend/src/lib/session.svelte.ts b/frontend/src/lib/session.svelte.ts new file mode 100644 index 0000000..db7fd90 --- /dev/null +++ b/frontend/src/lib/session.svelte.ts @@ -0,0 +1,28 @@ +import type { AdminUser } from './types'; + +const key = 'user'; +const key2 = 'username'; + +function login(user: AdminUser) { + localStorage.setItem(key, btoa(`${user.username}:${user.password_hash}`)); + localStorage.setItem(key2, user.username); +} + +function logout() { + localStorage.removeItem(key); + localStorage.removeItem(key2); +} + +function loggedIn() { + return localStorage.getItem(key) !== null; +} + +function name() { + return localStorage.getItem(key2) ?? ''; +} + +function auth() { + return localStorage.getItem(key); +} + +export default { login, logout, loggedIn, name, auth }; diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index e2aeefd..072609f 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -17,3 +17,13 @@ export interface Submission { data: Record; created_at?: string; } + +export interface LoginCredentials { + username: string; + password: string; +} + +export interface AdminUser { + username: string; + password_hash: string; +} diff --git a/frontend/src/routes/(auth)/+layout.ts b/frontend/src/routes/(auth)/+layout.ts new file mode 100644 index 0000000..342fa15 --- /dev/null +++ b/frontend/src/routes/(auth)/+layout.ts @@ -0,0 +1,8 @@ +import session from "$lib/session.svelte"; +import { redirect } from "@sveltejs/kit"; + +export async function load() { + if (!session.loggedIn()) { + redirect(307, "/login"); + } +} diff --git a/frontend/src/routes/(auth)/create/+page.svelte b/frontend/src/routes/(auth)/create/+page.svelte new file mode 100644 index 0000000..3428889 --- /dev/null +++ b/frontend/src/routes/(auth)/create/+page.svelte @@ -0,0 +1,149 @@ + + +
+

Create Form

+ +
+ + +
+ +

Fields

+ {#each fields as field, i} +
+ + + +
+ {/each} + +
+ + +
+
+ + diff --git a/frontend/src/routes/(auth)/form/[id]/+page.svelte b/frontend/src/routes/(auth)/form/[id]/+page.svelte new file mode 100644 index 0000000..5cab27c --- /dev/null +++ b/frontend/src/routes/(auth)/form/[id]/+page.svelte @@ -0,0 +1,179 @@ + + +
+ {#if form} +

{form.name}

+ + +

Submissions

+ {#if submissions.length > 0} +
    + {#each submissions as submission} +
  • + {formatSubmissionData(submission.data)} +
  • + {/each} +
+ {:else} +

No submissions yet.

+ {/if} + {:else} +
Loading...
+ {/if} +
+ + diff --git a/frontend/src/routes/form/[id]/+page.ts b/frontend/src/routes/(auth)/form/[id]/+page.ts similarity index 100% rename from frontend/src/routes/form/[id]/+page.ts rename to frontend/src/routes/(auth)/form/[id]/+page.ts diff --git a/frontend/src/routes/+layout.svelte b/frontend/src/routes/+layout.svelte new file mode 100644 index 0000000..a18244b --- /dev/null +++ b/frontend/src/routes/+layout.svelte @@ -0,0 +1,6 @@ + + +{@render children?.()} diff --git a/frontend/src/routes/+layout.ts b/frontend/src/routes/+layout.ts new file mode 100644 index 0000000..a3d1578 --- /dev/null +++ b/frontend/src/routes/+layout.ts @@ -0,0 +1 @@ +export const ssr = false; diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 06b4093..f6e752d 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -3,21 +3,88 @@ import { getForms } from '../lib/api'; import type { Form } from '../lib/types'; - let forms: any; + let forms: Form[] = []; onMount(async () => { forms = await getForms(); }); -

Form Management Tool

+
+

Formies

+ Create a New Form -Create a New Form + {#if forms.length > 0} + + {:else} +
+

No forms created yet. Create your first form to get started!

+
+ {/if} +
- + diff --git a/frontend/src/routes/+page.ts b/frontend/src/routes/+page.ts new file mode 100644 index 0000000..f25897e --- /dev/null +++ b/frontend/src/routes/+page.ts @@ -0,0 +1,7 @@ +import session from '$lib/session.svelte'; +import { redirect } from '@sveltejs/kit'; + +export async function load() { + const page = session.loggedIn() ? '/' : '/login'; + redirect(307, page); +} diff --git a/frontend/src/routes/create/+page.svelte b/frontend/src/routes/create/+page.svelte deleted file mode 100644 index 0eaa638..0000000 --- a/frontend/src/routes/create/+page.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - -

Create Form

- - - -

Fields

-{#each fields as field, i} -
- - - - -
-{/each} - - - diff --git a/frontend/src/routes/form/[id]/+page.svelte b/frontend/src/routes/form/[id]/+page.svelte deleted file mode 100644 index 6bd206f..0000000 --- a/frontend/src/routes/form/[id]/+page.svelte +++ /dev/null @@ -1,61 +0,0 @@ - - -

{form?.name}

- -{#if form} -
- {#each form.fields as field} -
- - - {#if field.field_type === 'text'} - - {:else if field.field_type === 'number'} - - {:else if field.field_type === 'date'} - - {:else if field.field_type === 'textarea'} - - {/if} -
- {/each} - -
- -

Submissions

-
    - {#each submissions as submission} -
  • {JSON.stringify(submission.data)}
  • - {/each} -
-{:else} -

Loading...

-{/if} diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte new file mode 100644 index 0000000..10245f4 --- /dev/null +++ b/frontend/src/routes/login/+page.svelte @@ -0,0 +1,105 @@ + + + + + diff --git a/frontend/src/routes/login/+page.ts b/frontend/src/routes/login/+page.ts new file mode 100644 index 0000000..bb67d7f --- /dev/null +++ b/frontend/src/routes/login/+page.ts @@ -0,0 +1,8 @@ +import session from '$lib/session.svelte'; +import { redirect } from '@sveltejs/kit'; + +export async function load() { + if (session.loggedIn()) { + redirect(307, '/'); + } +}