Link classroom user id to a person

This commit is contained in:
Araozu 2023-10-03 11:43:30 -05:00
parent b7684e193b
commit 816e26b790
7 changed files with 120 additions and 12 deletions

View File

@ -3,7 +3,7 @@ use rocket::http::Status;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use crate::json_result::JsonResult; use crate::json_result::JsonResult;
use crate::model::person::PersonCreate; use crate::model::person::{PersonCreate, PersonLink};
use crate::model::reniec_person::ReniecPerson; use crate::model::reniec_person::ReniecPerson;
use crate::{db, model::person::Person}; use crate::{db, model::person::Person};
@ -129,10 +129,21 @@ pub async fn get_by_dni(dni: i32) -> (Status, Json<JsonResult<Person>>) {
) )
} }
#[options("/person")]
pub fn options() -> Status { #[options("/person/link")]
Status::Ok pub fn options_p() -> Status { Status::Ok }
#[put("/person/link", format = "json", data = "<data>")]
pub async fn link_person(data: Json<PersonLink>) -> (Status, Json<JsonResult<()>>) {
match data.0.insert().await {
Ok(_) => (Status::Ok, JsonResult::ok(())),
Err(reason) => (Status::Ok, JsonResult::err(reason))
} }
}
#[options("/person")]
pub fn options() -> Status { Status::Ok }
#[post("/person", format = "json", data = "<person>")] #[post("/person", format = "json", data = "<person>")]
pub async fn create_person(person: Json<PersonCreate>) -> Status { pub async fn create_person(person: Json<PersonCreate>) -> Status {

View File

@ -21,7 +21,7 @@ impl Fairing for Cors {
response.set_header(Header::new("Access-Control-Allow-Origin", "*")); response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
response.set_header(Header::new( response.set_header(Header::new(
"Access-Control-Allow-Methods", "Access-Control-Allow-Methods",
"POST, GET, DELETE, OPTIONS", "POST, GET, PUT, DELETE, OPTIONS",
)); ));
response.set_header(Header::new("Access-Control-Allow-Headers", "Content-Type")); response.set_header(Header::new("Access-Control-Allow-Headers", "Content-Type"));
} }

View File

@ -45,6 +45,8 @@ async fn rocket() -> _ {
controller::person::get_by_dni, controller::person::get_by_dni,
controller::person::options, controller::person::options,
controller::person::create_person, controller::person::create_person,
controller::person::options_p,
controller::person::link_person,
controller::course::get_all, controller::course::get_all,
controller::register::insert_all, controller::register::insert_all,
controller::register::options, controller::register::options,

View File

@ -74,3 +74,32 @@ impl PersonCreate {
Ok(()) Ok(())
} }
} }
#[derive(Deserialize)]
pub struct PersonLink {
pub person_id: i32,
pub person_classroom_id: i32,
}
impl PersonLink {
pub async fn insert(&self) -> Result<(), String> {
let db = db();
let res = sqlx::query!(
"UPDATE person SET person_classroom_id = ? WHERE person_id = ?",
self.person_classroom_id,
self.person_id,
)
.execute(db)
.await;
match res {
Ok(_) => Ok(()),
Err(error) => {
eprintln!("Error linking person to classroom: {:?}", error);
Err(format!("Error vinculando persona."))
}
}
}
}

View File

@ -9,6 +9,7 @@ import { SpinnerGapIcon } from "../icons/SpinnerGapIcon";
import { QuestionIcon } from "../icons/QuestionIcon"; import { QuestionIcon } from "../icons/QuestionIcon";
import { JsonResult } from "../types/JsonResult"; import { JsonResult } from "../types/JsonResult";
import { XcircleIcon } from "../icons/XCircleIcon"; import { XcircleIcon } from "../icons/XCircleIcon";
import { LoadingStatus, backend, useLoading, wait } from "../utils/functions";
type TabType = "Vinculate" | "Create"; type TabType = "Vinculate" | "Create";
@ -20,8 +21,14 @@ export function OnlineClassroom() {
<Search setPerson={setPerson} /> <Search setPerson={setPerson} />
<div> <div>
<Show when={person() !== null && !person()!.person_classroom_id}> <Show when={person() !== null && person()!.person_classroom_id === undefined}>
<ClassroomUser person={person()!} /> <ClassroomUser
person={person()!}
onLink={(classroom_id) => setPerson((p) => ({...p!, person_classroom_id: classroom_id}))}
/>
</Show>
<Show when={person() !== null && person()!.person_classroom_id !== undefined}>
<p>Person has classroom_id</p>
</Show> </Show>
</div> </div>
@ -31,7 +38,7 @@ export function OnlineClassroom() {
function ClassroomUser(props: {person: Person}) { function ClassroomUser(props: {person: Person, onLink: (classroom_id: number) => void,}) {
const [active, setActive] = createSignal<TabType>("Vinculate"); const [active, setActive] = createSignal<TabType>("Vinculate");
return ( return (
@ -46,6 +53,8 @@ function ClassroomUser(props: {person: Person}) {
<Show when={active() === "Vinculate"}> <Show when={active() === "Vinculate"}>
<ClassroomVinculation <ClassroomVinculation
person_surname={`${props.person.person_paternal_surname} ${props.person.person_maternal_surname}`} person_surname={`${props.person.person_paternal_surname} ${props.person.person_maternal_surname}`}
personId={props.person.person_id}
onLink={props.onLink}
/> />
</Show> </Show>
<Show when={active() === "Create"}> <Show when={active() === "Create"}>
@ -59,7 +68,7 @@ function ClassroomUser(props: {person: Person}) {
} }
type Status = "Init" | "Ok" | "Loading" | "Error"; type Status = "Init" | "Ok" | "Loading" | "Error";
function ClassroomVinculation(props: {person_surname: string}) { function ClassroomVinculation(props: {person_surname: string, personId: number, onLink: (classroom_id: number) => void,}) {
const [classroomUsers, setClassroomUsers] = createSignal<ClassroomRegistrationUser[]>([]); const [classroomUsers, setClassroomUsers] = createSignal<ClassroomRegistrationUser[]>([]);
const [error, setError] = createSignal(""); const [error, setError] = createSignal("");
const [status, setStatus] = createSignal<Status>("Init"); const [status, setStatus] = createSignal<Status>("Init");
@ -103,7 +112,13 @@ function ClassroomVinculation(props: {person_surname: string}) {
</div> </div>
</Show> </Show>
<For each={classroomUsers()}> <For each={classroomUsers()}>
{(u) => <ClassroomSingleUser user={u} />} {(u) => (
<ClassroomSingleUser
user={u}
personId={props.personId}
onLink={props.onLink}
/>
)}
</For> </For>
</Show> </Show>
@ -121,7 +136,42 @@ function ClassroomVinculation(props: {person_surname: string}) {
function ClassroomSingleUser(props: {user: ClassroomRegistrationUser}) { function ClassroomSingleUser(props: {
user: ClassroomRegistrationUser,
onLink: (classroom_id: number) => void,
personId: number,
}) {
const {setError, status, setStatus} = useLoading();
const linkUser = async() => {
setStatus(LoadingStatus.Loading);
if (import.meta.env.DEV) await wait(1500);
backend.put<JsonResult<null>>(
"/api/person/link",
{
person_id: props.personId,
person_classroom_id: parseInt(props.user.user_id, 10),
},
)
.then((response) => {
if (response.status === 200) {
setStatus(LoadingStatus.Ok);
props.onLink(parseInt(props.user.user_id, 10));
} else {
console.error(response.data);
setError(response.data.Err.reason);
setStatus(LoadingStatus.Error);
}
})
.catch((err) => {
setError(`Error fatal: ${err.message}`);
console.error(err);
setStatus(LoadingStatus.Error);
});
};
return ( return (
<div <div
class="hover:bg-c-surface-variant hover:text-c-on-surface-variant transition-colors class="hover:bg-c-surface-variant hover:text-c-on-surface-variant transition-colors
@ -145,6 +195,8 @@ function ClassroomSingleUser(props: {user: ClassroomRegistrationUser}) {
<button <button
title="Vincular usuario" title="Vincular usuario"
class="border-2 border-c-transparent hover:border-c-primary transition-colors rounded" class="border-2 border-c-transparent hover:border-c-primary transition-colors rounded"
onclick={linkUser}
disabled={status() === LoadingStatus.Loading}
> >
<LinkIcon fill="var(--c-primary)" /> <LinkIcon fill="var(--c-primary)" />
</button> </button>

View File

@ -5,6 +5,6 @@ export type Person = {
person_names: string person_names: string
person_paternal_surname: string person_paternal_surname: string
person_maternal_surname: string person_maternal_surname: string
person_classroom_id: string | undefined person_classroom_id: number | undefined
} }

View File

@ -1,4 +1,5 @@
import axios from "axios"; import axios from "axios";
import { createSignal } from "solid-js";
// YYYY-MM-DD to DD/MM/YYYY // YYYY-MM-DD to DD/MM/YYYY
@ -14,3 +15,16 @@ export const backend = axios.create({
export function wait(ms: number): Promise<void> { export function wait(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
export enum LoadingStatus {
Init,
Loading,
Ok,
Error,
}
export function useLoading() {
const [status, setStatus] = createSignal(LoadingStatus.Init);
const [error, setError] = createSignal("");
return {error, setError, status, setStatus};
}