Compare commits
2 Commits
856cb1ee59
...
3ba56ca232
Author | SHA1 | Date | |
---|---|---|---|
|
3ba56ca232 | ||
|
6094beb199 |
74
backend/Cargo.lock
generated
74
backend/Cargo.lock
generated
@ -19,6 +19,21 @@ 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"
|
||||||
@ -464,6 +479,19 @@ 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"
|
||||||
@ -511,8 +539,11 @@ 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",
|
||||||
@ -547,6 +578,7 @@ dependencies = [
|
|||||||
"futures-task",
|
"futures-task",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -620,6 +652,12 @@ 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"
|
||||||
@ -649,6 +687,12 @@ 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"
|
||||||
@ -804,6 +848,17 @@ 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"
|
||||||
@ -837,6 +892,7 @@ 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",
|
||||||
]
|
]
|
||||||
@ -1274,6 +1330,15 @@ 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"
|
||||||
@ -1439,6 +1504,15 @@ 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"
|
||||||
|
@ -5,8 +5,11 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "4.0"
|
actix-web = "4.0"
|
||||||
rusqlite = "0.29"
|
rusqlite = { version = "0.29", features = ["bundled"] }
|
||||||
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"
|
Binary file not shown.
@ -10,6 +10,7 @@ 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();
|
||||||
@ -34,7 +35,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: String = row.get(0)?;
|
let id: Option<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();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use actix_files as fs;
|
use actix_cors::Cors;
|
||||||
|
// 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};
|
||||||
|
|
||||||
@ -9,6 +10,8 @@ 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"),
|
||||||
));
|
));
|
||||||
@ -16,8 +19,14 @@ 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(
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Form {
|
pub struct Form {
|
||||||
pub id: String,
|
pub id: Option<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
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,85 @@
|
|||||||
import axios from 'axios';
|
// api.ts
|
||||||
import type { Form, Submission } from './types';
|
const API_BASE_URL = 'http://127.0.0.1:8080';
|
||||||
|
|
||||||
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 })
|
||||||
|
});
|
||||||
|
|
||||||
// Fetch all forms
|
if (!response.ok) {
|
||||||
export async function fetchForms(): Promise<Form[]> {
|
throw new Error(`Error creating form: ${response.statusText}`);
|
||||||
const response = await axios.get(`${API_BASE}/forms`);
|
}
|
||||||
return response.data;
|
|
||||||
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new form
|
/**
|
||||||
export async function createForm(form: Omit<Form, 'id' | 'created_at'>): Promise<string> {
|
* Get all forms.
|
||||||
const response = await axios.post(`${API_BASE}/forms`, form);
|
* @returns An array of forms.
|
||||||
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
|
/**
|
||||||
export async function fetchSubmissions(formId: string): Promise<Submission[]> {
|
* Submit a form.
|
||||||
const response = await axios.get(`${API_BASE}/forms/${formId}/submissions`);
|
* @param formId The ID of the form to submit.
|
||||||
return response.data;
|
* @param data The submission data in JSON format.
|
||||||
|
* @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
|
/**
|
||||||
export async function submitForm(formId: string, data: Record<string, unknown>): Promise<string> {
|
* Get all submissions for a specific form.
|
||||||
const response = await axios.post(`${API_BASE}/forms/${formId}/submissions`, data);
|
* @param formId The ID of the form.
|
||||||
return response.data; // Returns the submission ID
|
* @returns An array of submissions for the form.
|
||||||
|
*/
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { fetchForms } from '../lib/api';
|
import { getForms } from '../lib/api';
|
||||||
import type { Form } from '../lib/types';
|
import type { Form } from '../lib/types';
|
||||||
|
|
||||||
let forms: Form[] = [];
|
let forms: any;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
forms = await fetchForms();
|
forms = await getForms();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -6,13 +6,24 @@
|
|||||||
let fields: FormField[] = [];
|
let fields: FormField[] = [];
|
||||||
|
|
||||||
function addField() {
|
function addField() {
|
||||||
fields.push({ label: '', name: '', field_type: 'text' });
|
// Use a new array assignment to trigger reactivity
|
||||||
|
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() {
|
||||||
await createForm({ name, fields });
|
try {
|
||||||
alert('Form created successfully!');
|
await createForm(name, fields);
|
||||||
location.href = '/';
|
alert('Form created successfully!');
|
||||||
|
location.href = '/';
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create form:', error);
|
||||||
|
alert('An error occurred while creating the form.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -20,7 +31,7 @@
|
|||||||
|
|
||||||
<label>
|
<label>
|
||||||
Form Name:
|
Form Name:
|
||||||
<input type="text" bind:value={name} />
|
<input type="text" bind:value={name} placeholder="Enter form name" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<h2>Fields</h2>
|
<h2>Fields</h2>
|
||||||
@ -28,11 +39,11 @@
|
|||||||
<div>
|
<div>
|
||||||
<label>
|
<label>
|
||||||
Label:
|
Label:
|
||||||
<input type="text" bind:value={field.label} />
|
<input type="text" bind:value={field.label} placeholder="Enter field label" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Name:
|
Name:
|
||||||
<input type="text" bind:value={field.name} />
|
<input type="text" bind:value={field.name} placeholder="Enter field name" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Type:
|
Type:
|
||||||
@ -43,8 +54,9 @@
|
|||||||
<option value="textarea">Textarea</option>
|
<option value="textarea">Textarea</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<button on:click={() => fields.splice(i, 1)}>Remove</button>
|
<button on:click={() => removeField(i)}>Remove</button>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<button on:click={addField}>Add Field</button>
|
<button on:click={addField}>Add Field</button>
|
||||||
<button on:click={saveForm}>Save Form</button>
|
<button on:click={saveForm} disabled={!name || fields.length === 0}> Save Form </button>
|
||||||
|
@ -1,22 +1,30 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { fetchForms, fetchSubmissions, submitForm } from '../../../lib/api';
|
import { getForms, getSubmissions, 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 };
|
||||||
let form: Form | null = null;
|
console.log('params.id:', params);
|
||||||
let submissions: Submission[] = [];
|
let form: any | null = null;
|
||||||
|
let submissions: any[] = [];
|
||||||
let responseData: Record<string, any> = {};
|
let responseData: Record<string, any> = {};
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
form = await fetchForms().then((forms) => forms.find((f) => f.id === params.id) || null);
|
const { id } = $page.params; // Use $page.params to access route parameters
|
||||||
submissions = await fetchSubmissions(params.id);
|
if (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() {
|
||||||
await submitForm(params.id, responseData);
|
const { id } = $page.params; // Use $page.params to access route parameters
|
||||||
|
await submitForm(id, responseData);
|
||||||
alert('Response submitted successfully!');
|
alert('Response submitted successfully!');
|
||||||
submissions = await fetchSubmissions(params.id); // Refresh submissions
|
submissions = await getSubmissions(params.id); // Refresh submissions
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
5
frontend/src/routes/form/[id]/+page.ts
Normal file
5
frontend/src/routes/form/[id]/+page.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export function load({ params }) {
|
||||||
|
return {
|
||||||
|
params
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user