Compare commits

..

No commits in common. "3ba56ca23261f3d03fcf8affd6bda21b1383c778" and "856cb1ee596c44d643d18b2a04de3ec51a948aae" have entirely different histories.

11 changed files with 45 additions and 214 deletions

74
backend/Cargo.lock generated
View File

@ -19,21 +19,6 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "actix-cors"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0346d8c1f762b41b458ed3145eea914966bb9ad20b9be0d6d463b20d45586370"
dependencies = [
"actix-utils",
"actix-web",
"derive_more",
"futures-util",
"log",
"once_cell",
"smallvec",
]
[[package]] [[package]]
name = "actix-files" name = "actix-files"
version = "0.6.6" version = "0.6.6"
@ -479,19 +464,6 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "env_logger"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
dependencies = [
"humantime",
"is-terminal",
"log",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -539,11 +511,8 @@ dependencies = [
name = "formies_be" name = "formies_be"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix-cors",
"actix-files", "actix-files",
"actix-web", "actix-web",
"env_logger",
"log",
"rusqlite", "rusqlite",
"serde", "serde",
"serde_json", "serde_json",
@ -578,7 +547,6 @@ dependencies = [
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
] ]
[[package]] [[package]]
@ -652,12 +620,6 @@ dependencies = [
"hashbrown 0.14.5", "hashbrown 0.14.5",
] ]
[[package]]
name = "hermit-abi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.12" version = "0.2.12"
@ -687,12 +649,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "icu_collections" name = "icu_collections"
version = "1.5.0" version = "1.5.0"
@ -848,17 +804,6 @@ dependencies = [
"hashbrown 0.15.2", "hashbrown 0.15.2",
] ]
[[package]]
name = "is-terminal"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
dependencies = [
"hermit-abi",
"libc",
"windows-sys",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.14" version = "1.0.14"
@ -892,7 +837,6 @@ version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
dependencies = [ dependencies = [
"cc",
"pkg-config", "pkg-config",
"vcpkg", "vcpkg",
] ]
@ -1330,15 +1274,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.37" version = "0.3.37"
@ -1504,15 +1439,6 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"

View File

@ -5,11 +5,8 @@ edition = "2021"
[dependencies] [dependencies]
actix-web = "4.0" actix-web = "4.0"
rusqlite = { version = "0.29", features = ["bundled"] } rusqlite = "0.29"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
uuid = { version = "1.0", features = ["v4"] } uuid = { version = "1.0", features = ["v4"] }
actix-files = "0.6" actix-files = "0.6"
actix-cors = "0.6"
env_logger = "0.10" # Check for the latest version
log = "0.4"

View File

@ -10,7 +10,6 @@ pub async fn create_form(
db: web::Data<Arc<Mutex<Connection>>>, db: web::Data<Arc<Mutex<Connection>>>,
form: web::Json<Form>, form: web::Json<Form>,
) -> impl Responder { ) -> impl Responder {
println!("Received form: {:?}", form);
let conn = db.lock().unwrap(); // Lock the Mutex to access the database let conn = db.lock().unwrap(); // Lock the Mutex to access the database
let form_id = Uuid::new_v4().to_string(); let form_id = Uuid::new_v4().to_string();
let form_json = serde_json::to_string(&form.fields).unwrap(); let form_json = serde_json::to_string(&form.fields).unwrap();
@ -35,7 +34,7 @@ pub async fn get_forms(db: web::Data<Arc<Mutex<Connection>>>) -> impl Responder
let forms_iter = stmt let forms_iter = stmt
.query_map([], |row| { .query_map([], |row| {
let id: Option<String> = row.get(0)?; let id: String = row.get(0)?;
let name: String = row.get(1)?; let name: String = row.get(1)?;
let fields: String = row.get(2)?; let fields: String = row.get(2)?;
let fields = serde_json::from_str(&fields).unwrap(); let fields = serde_json::from_str(&fields).unwrap();

View File

@ -1,5 +1,4 @@
use actix_cors::Cors; use actix_files as fs;
// use actix_files as fs;
use actix_web::{web, App, HttpServer}; use actix_web::{web, App, HttpServer};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -10,8 +9,6 @@ mod models;
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
// Initialize the database connection // Initialize the database connection
env_logger::init();
let db = Arc::new(Mutex::new( let db = Arc::new(Mutex::new(
db::init_db().expect("Failed to initialize the database"), db::init_db().expect("Failed to initialize the database"),
)); ));
@ -19,14 +16,8 @@ async fn main() -> std::io::Result<()> {
// Start the Actix-Web server // Start the Actix-Web server
HttpServer::new(move || { HttpServer::new(move || {
App::new() App::new()
.wrap(
Cors::default()
.allow_any_origin()
.allow_any_header()
.allow_any_method(),
)
.app_data(web::Data::new(db.clone())) .app_data(web::Data::new(db.clone()))
// .service(fs::Files::new("/", "./frontend/public").index_file("index.html")) .service(fs::Files::new("/", "./frontend/public").index_file("index.html"))
.route("/forms", web::post().to(handlers::create_form)) .route("/forms", web::post().to(handlers::create_form))
.route("/forms", web::get().to(handlers::get_forms)) .route("/forms", web::get().to(handlers::get_forms))
.route( .route(

View File

@ -1,8 +1,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize)]
pub struct Form { pub struct Form {
pub id: Option<String>, pub id: String,
pub name: String, pub name: String,
pub fields: serde_json::Value, // JSON array of form fields pub fields: serde_json::Value, // JSON array of form fields
} }

View File

@ -1,85 +1,28 @@
// api.ts import axios from 'axios';
const API_BASE_URL = 'http://127.0.0.1:8080'; import type { Form, Submission } from './types';
/** const API_BASE = 'http://localhost:8080'; // Backend URL
* Create a new form.
* @param name The name of the form.
* @param fields The fields of the form in JSON format.
* @returns The ID of the created form.
*/
export async function createForm(name: string, fields: unknown): Promise<string> {
const response = await fetch(`${API_BASE_URL}/forms`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name, fields })
});
if (!response.ok) { // Fetch all forms
throw new Error(`Error creating form: ${response.statusText}`); export async function fetchForms(): Promise<Form[]> {
} const response = await axios.get(`${API_BASE}/forms`);
return response.data;
return await response.json();
} }
/** // Create a new form
* Get all forms. export async function createForm(form: Omit<Form, 'id' | 'created_at'>): Promise<string> {
* @returns An array of forms. const response = await axios.post(`${API_BASE}/forms`, form);
*/ return response.data; // Returns the created form's ID
export async function getForms(): Promise<unknown[]> {
const response = await fetch(`${API_BASE_URL}/forms`, {
method: 'GET',
headers: {
Accept: 'application/json'
}
});
if (!response.ok) {
throw new Error(`Error fetching forms: ${response.statusText}`);
}
return await response.json();
} }
/** // Fetch form submissions
* Submit a form. export async function fetchSubmissions(formId: string): Promise<Submission[]> {
* @param formId The ID of the form to submit. const response = await axios.get(`${API_BASE}/forms/${formId}/submissions`);
* @param data The submission data in JSON format. return response.data;
* @returns The ID of the created submission.
*/
export async function submitForm(formId: string, data: unknown): Promise<string> {
const response = await fetch(`${API_BASE_URL}/forms/${formId}/submissions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`Error submitting form: ${response.statusText}`);
}
return await response.json();
} }
/** // Submit a form
* Get all submissions for a specific form. export async function submitForm(formId: string, data: Record<string, unknown>): Promise<string> {
* @param formId The ID of the form. const response = await axios.post(`${API_BASE}/forms/${formId}/submissions`, data);
* @returns An array of submissions for the form. return response.data; // Returns the submission ID
*/
export async function getSubmissions(formId: string): Promise<unknown[]> {
const response = await fetch(`${API_BASE_URL}/forms/${formId}/submissions`, {
method: 'GET',
headers: {
Accept: 'application/json'
}
});
if (!response.ok) {
throw new Error(`Error fetching submissions: ${response.statusText}`);
}
return await response.json();
} }

View File

@ -1,12 +1,12 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { getForms } from '../lib/api'; import { fetchForms } from '../lib/api';
import type { Form } from '../lib/types'; import type { Form } from '../lib/types';
let forms: any; let forms: Form[] = [];
onMount(async () => { onMount(async () => {
forms = await getForms(); forms = await fetchForms();
}); });
</script> </script>

View File

@ -6,24 +6,13 @@
let fields: FormField[] = []; let fields: FormField[] = [];
function addField() { function addField() {
// Use a new array assignment to trigger reactivity fields.push({ label: '', name: '', field_type: 'text' });
fields = [...fields, { label: '', name: '', field_type: 'text' }];
}
function removeField(index: number) {
// Reassign to trigger reactivity
fields = fields.filter((_, i) => i !== index);
} }
async function saveForm() { async function saveForm() {
try { await createForm({ name, fields });
await createForm(name, fields); alert('Form created successfully!');
alert('Form created successfully!'); location.href = '/';
location.href = '/';
} catch (error) {
console.error('Failed to create form:', error);
alert('An error occurred while creating the form.');
}
} }
</script> </script>
@ -31,7 +20,7 @@
<label> <label>
Form Name: Form Name:
<input type="text" bind:value={name} placeholder="Enter form name" /> <input type="text" bind:value={name} />
</label> </label>
<h2>Fields</h2> <h2>Fields</h2>
@ -39,11 +28,11 @@
<div> <div>
<label> <label>
Label: Label:
<input type="text" bind:value={field.label} placeholder="Enter field label" /> <input type="text" bind:value={field.label} />
</label> </label>
<label> <label>
Name: Name:
<input type="text" bind:value={field.name} placeholder="Enter field name" /> <input type="text" bind:value={field.name} />
</label> </label>
<label> <label>
Type: Type:
@ -54,9 +43,8 @@
<option value="textarea">Textarea</option> <option value="textarea">Textarea</option>
</select> </select>
</label> </label>
<button on:click={() => removeField(i)}>Remove</button> <button on:click={() => fields.splice(i, 1)}>Remove</button>
</div> </div>
{/each} {/each}
<button on:click={addField}>Add Field</button> <button on:click={addField}>Add Field</button>
<button on:click={saveForm} disabled={!name || fields.length === 0}> Save Form </button> <button on:click={saveForm}>Save Form</button>

View File

@ -1,30 +1,22 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { getForms, getSubmissions, submitForm } from '../../../lib/api'; import { fetchForms, fetchSubmissions, submitForm } from '../../../lib/api';
import type { Form, Submission } from '../../../lib/types'; import type { Form, Submission } from '../../../lib/types';
import { page } from '$app/stores';
export let params: { id: string }; export let params: { id: string };
console.log('params.id:', params); let form: Form | null = null;
let form: any | null = null; let submissions: Submission[] = [];
let submissions: any[] = [];
let responseData: Record<string, any> = {}; let responseData: Record<string, any> = {};
onMount(async () => { onMount(async () => {
const { id } = $page.params; // Use $page.params to access route parameters form = await fetchForms().then((forms) => forms.find((f) => f.id === params.id) || null);
if (id) { submissions = await fetchSubmissions(params.id);
form = await getForms().then((forms) => forms.find((f: any) => f.id === id) || null);
submissions = await getSubmissions(id);
} else {
console.error('Route parameter id is missing');
}
}); });
async function submitResponse() { async function submitResponse() {
const { id } = $page.params; // Use $page.params to access route parameters await submitForm(params.id, responseData);
await submitForm(id, responseData);
alert('Response submitted successfully!'); alert('Response submitted successfully!');
submissions = await getSubmissions(params.id); // Refresh submissions submissions = await fetchSubmissions(params.id); // Refresh submissions
} }
</script> </script>

View File

@ -1,5 +0,0 @@
export function load({ params }) {
return {
params
};
}