[Certs] FE & BE Mock for registers

master
Araozu 2023-08-28 17:28:58 -05:00
parent fadbfbc7be
commit 81157d53de
14 changed files with 186 additions and 66 deletions

View File

@ -7,12 +7,19 @@ pub async fn get_all() -> Json<Vec<Course>> {
// TODO: get from database // TODO: get from database
let c = Course { let c = Course {
course_id: 1, course_id: 1,
course_code: 322,
course_name: "4x4".to_string(), course_name: "4x4".to_string(),
course_display_name: "Manejo en 4x4 road danger".to_string(), course_display_name: "Manejo en 4x4 road danger".to_string(),
course_days_amount: 2, course_days_amount: 2,
course_has_custom_label: false, course_has_custom_label: false,
}; };
Json(vec![c.clone(), c]) let c2 = Course {
course_id: 2,
course_name: "Mec. Basica".to_string(),
course_display_name: "Mecánica Básica".to_string(),
course_days_amount: 2,
course_has_custom_label: false,
};
Json(vec![c, c2])
} }

View File

@ -1,2 +1,3 @@
pub mod course; pub mod course;
pub mod person; pub mod person;
pub mod register;

View File

@ -0,0 +1,38 @@
use rocket::{serde::json::Json, http::Status};
use crate::model::register::{RegisterCreate, Register};
#[options("/register/batch")]
pub fn options() -> Status {
Status::Ok
}
#[post("/register/batch", format = "json", data = "<data>")]
pub async fn insert_all(data: Json<Vec<RegisterCreate>>) -> Status {
Status::Ok
}
#[get("/register/<dni>")]
pub async fn get_by_dni(dni: i32) -> Json<Vec<Register>> {
let r1 = Register {
register_id: 1,
register_code: 322,
register_creation_date: "2021-01-01".to_string(),
register_display_date: "2021-01-01".to_string(),
register_custom_label: "".to_string(),
register_person_id: 1,
register_course_id: 1,
};
let r2 = Register {
register_id: 2,
register_code: 323,
register_creation_date: "2021-01-01".to_string(),
register_display_date: "2021-01-03".to_string(),
register_custom_label: "".to_string(),
register_person_id: 1,
register_course_id: 2,
};
Json(vec![r1, r2])
}

View File

@ -40,5 +40,8 @@ fn rocket() -> _ {
.mount("/api", routes![ .mount("/api", routes![
controller::person::get_by_dni, controller::person::get_by_dni,
controller::course::get_all, controller::course::get_all,
controller::register::insert_all,
controller::register::options,
controller::register::get_by_dni,
]) ])
} }

View File

@ -4,11 +4,6 @@ use rocket::serde::Serialize;
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub struct Course { pub struct Course {
pub course_id: i32, pub course_id: i32,
/// Display code, shown on the certificate.
/// Currently a 4-digit number. After 9999, it will be a 4-digit hex number.
///
/// Example: `0322`
pub course_code: i32,
/// Internal name, shown in the admin panel /// Internal name, shown in the admin panel
/// ///
/// Example: `4x4` /// Example: `4x4`

View File

@ -1,2 +1,3 @@
pub mod course; pub mod course;
pub mod person; pub mod person;
pub mod register;

View File

@ -0,0 +1,36 @@
use rocket::serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone)]
#[serde(crate = "rocket::serde")]
/// Represents a single register send by the frontend
/// to create a new register in the database
pub struct RegisterCreate {
person_id: i32,
course_id: i32,
/// YYYY-MM-DD
date: String
}
#[derive(Serialize, Deserialize, Clone)]
#[serde(crate = "rocket::serde")]
pub struct Register {
pub register_id: i32,
/// Display code, shown on the certificate.
/// Currently a 4-digit number. After 9999, it will be a 4-digit hex number.
///
/// Example: `0322``
pub register_code: i32,
/// Date of creation of the register, in YYYY-MM-DD format
pub register_creation_date: String,
/// Date shown on the certificate, in YYYY-MM-DD format
pub register_display_date: String,
/// Some course's names can be extended with a label.
/// Used in machinery courses, where the course name is the type of machinery,
/// and the custom label the manufacturer and series (i.e. `320D CAT`).
pub register_custom_label: String,
/// Foreign key to the person table
pub register_person_id: i32,
/// Foreign key to the course table
pub register_course_id: i32,
}

2
frontend/.env.local Normal file
View File

@ -0,0 +1,2 @@
VITE_BACKEND_URL=http://localhost:8000

View File

@ -7,7 +7,10 @@ const App: Component = () => (
<div class="grid grid-cols-[5rem_auto]"> <div class="grid grid-cols-[5rem_auto]">
<NavRail /> <NavRail />
<Routes> <Routes>
<Route path="/" component={() => <p>En construccion</p>} />
<Route path="/certs" component={Certs} /> <Route path="/certs" component={Certs} />
<Route path="/accesos" component={() => <p>En construccion</p>} />
<Route path="/escaneo" component={() => <p>En construccion</p>} />
</Routes> </Routes>
</div> </div>
); );

View File

@ -67,7 +67,6 @@ export function ManualRegistration(props: {personId: number | null, onAdd: (v: [
</div> </div>
<div class="relative"> <div class="relative">
<input <input
ref={datePicker}
id="create-date" id="create-date"
class="bg-c-surface text-c-on-surface border border-c-outline rounded-lg p-2 font-mono w-full class="bg-c-surface text-c-on-surface border border-c-outline rounded-lg p-2 font-mono w-full
disabled:opacity-50 disabled:cursor-not-allowed" disabled:opacity-50 disabled:cursor-not-allowed"
@ -80,21 +79,25 @@ export function ManualRegistration(props: {personId: number | null, onAdd: (v: [
</div> </div>
</div> </div>
<input <div>
class="bg-c-primary text-c-on-primary px-4 py-2 rounded-full cursor-pointer
disabled:opacity-50 disabled:cursor-not-allowed"
type="submit"
value="Agregar"
disabled={props.personId === null}
/>
</form>
<p
class="my-2 p-1 rounded w-fit mx-4 bg-c-error text-c-on-error" <input
style={{opacity: error() === "" ? "0" : "1", "user-select": "none"}} class="bg-c-primary text-c-on-primary px-4 py-2 rounded-full cursor-pointer
> disabled:opacity-50 disabled:cursor-not-allowed"
{error()}&nbsp; type="submit"
</p> value="Agregar"
disabled={props.personId === null}
/>
<p
class="my-2 p-1 w-fit mx-4 text-c-error inline-block"
// style={{opacity: error() === "" ? "0" : "1", "user-select": "none"}}
>
{error()}&nbsp;
</p>
</div>
</form>
</> </>
); );
} }

View File

@ -2,6 +2,7 @@ import { FilledCard } from "../../components/FilledCard";
import { For } from "solid-js"; import { For } from "solid-js";
import { XIcon } from "../../icons/XIcon"; import { XIcon } from "../../icons/XIcon";
import { allCourses } from "../../utils/allCourses"; import { allCourses } from "../../utils/allCourses";
import { RegisterBatchCreate } from "../../types/Register";
function isoDateToLocalDate(date: string): string { function isoDateToLocalDate(date: string): string {
@ -13,19 +14,18 @@ export function RegisterPreview(props: {selections: Array<[number, string]>, per
const submit = async() => { const submit = async() => {
console.log("Submit..."); console.log("Submit...");
// TODO: Send all register requests at once const registers: RegisterBatchCreate = props.selections.map(([courseId, date]) => ({
for (const [courseId, date] of props.selections) { person_id: props.personId!,
const result = await defaultNewRegisterFn( course_id: courseId,
props.personId ?? -1, date,
courseId, }));
date,
);
if (result === null) { const result = await createRegisters(registers);
console.log("Success");
} else { if (result === null) {
console.log(`error. ${result}`); console.log("Success");
} } else {
console.log(`error. ${result}`);
} }
props.onRegister(); props.onRegister();
@ -74,17 +74,13 @@ function Register(props: {courseId: number, date: string, onDelete: (v: number)
} }
async function defaultNewRegisterFn(personId: number, subjectId: number, date: string): Promise<null | string> { async function createRegisters(data: RegisterBatchCreate): Promise<null | string> {
const response = await fetch("/certificate", { const response = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/register/batch`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify(data),
personId,
subjectId,
date,
}),
}); });
if (response.ok) { if (response.ok) {

View File

@ -1,25 +0,0 @@
import { DownloadIcon } from "../icons/DownloadIcon";
export function Registers() {
return (
<div class="m-4 p-4 rounded-md">
<h3 class="text-xl font-medium py-2">
SUMA BERNAL, MAIKOL
</h3>
<div class="flex flex-wrap justify-start gap-2">
<div class="inline-block w-[12rem] p-1 border border-c-outline rounded-md">
<button class="rounded-full bg-c-primary-container hover:bg-c-primary transition-colors h-12 w-12">
<DownloadIcon fill="var(--c-on-primary-container)" />
</button>
<div class="inline-block h-12 w-32 pl-2 align-middle">
<p class="font-bold">Matpel 2</p>
<p class="font-mono text-sm">12/08/2023 - 6486</p>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,31 @@
import { DownloadIcon } from "../../icons/DownloadIcon";
import { Register } from "../../types/Register";
export function Registers() {
return (
<div class="m-4 p-4 rounded-md">
<h3 class="text-xl font-medium py-2">
SUMA BERNAL, MAIKOL
</h3>
<div class="flex flex-wrap justify-start gap-2">
<RegisterEl />
<RegisterEl />
<RegisterEl />
</div>
</div>
);
}
function RegisterEl(props: {register: Register}) {
return (
<div class="inline-block w-[12rem] p-1 border border-c-outline rounded-md">
<button class="rounded-full bg-c-primary-container hover:bg-c-primary transition-colors h-12 w-12">
<DownloadIcon fill="var(--c-on-primary-container)" />
</button>
<div class="inline-block h-12 w-32 pl-2 align-middle">
<p class="font-bold">Matpel 2</p>
<p class="font-mono text-sm">12/08/2023 - 6486</p>
</div>
</div>
);
}

View File

@ -0,0 +1,29 @@
export type RegisterBatchCreate = Array<{
person_id: number,
course_id: number,
/**
* YYYY-MM-DD
*/
date: string,
}>
export type Register = {
register_id: number,
/// Display code, shown on the certificate.
/// Currently a 4-digit number. After 9999, it will be a 4-digit hex number.
///
/// Example: `0322``
register_code: number,
/// Date of creation of the register, in YYYY-MM-DD format
register_creation_date: string,
/// Date shown on the certificate, in YYYY-MM-DD format
register_display_date: string,
/// Some course's names can be extended with a label.
/// Used in machinery courses, where the course name is the type of machinery,
/// and the custom label the manufacturer and series (i.e. `320D CAT`).
register_custom_label: string,
/// Foreign key to the person table
register_person_id: number,
/// Foreign key to the course table
register_course_id: number,
}