2023-09-30 16:16:20 +00:00
|
|
|
import { For, Show, createSignal, onMount } from "solid-js";
|
2023-09-21 21:06:31 +00:00
|
|
|
import { Search } from "../certs/Search";
|
|
|
|
import { Person } from "../types/Person";
|
2023-09-26 21:13:30 +00:00
|
|
|
import { FilledCard } from "../components/FilledCard";
|
|
|
|
import { LinkIcon } from "../icons/LinkIcon";
|
|
|
|
import { ClassroomUserCreation } from "./ClassroomUserCreation";
|
2023-09-30 16:16:20 +00:00
|
|
|
import { ClassroomRegistrationUser } from "../types/ClassroomRegistrationUser";
|
2023-10-02 16:22:12 +00:00
|
|
|
import { SpinnerGapIcon } from "../icons/SpinnerGapIcon";
|
|
|
|
import { QuestionIcon } from "../icons/QuestionIcon";
|
|
|
|
import { JsonResult } from "../types/JsonResult";
|
|
|
|
import { XcircleIcon } from "../icons/XCircleIcon";
|
2023-10-03 16:43:30 +00:00
|
|
|
import { LoadingStatus, backend, useLoading, wait } from "../utils/functions";
|
2023-09-26 21:13:30 +00:00
|
|
|
|
|
|
|
type TabType = "Vinculate" | "Create";
|
2023-09-21 21:06:31 +00:00
|
|
|
|
|
|
|
export function OnlineClassroom() {
|
|
|
|
const [person, setPerson] = createSignal<Person | null>(null);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div class="grid grid-cols-[16rem_25rem_1fr]">
|
|
|
|
<Search setPerson={setPerson} />
|
2023-09-21 22:07:18 +00:00
|
|
|
<div>
|
2023-09-26 21:13:30 +00:00
|
|
|
|
2023-10-03 16:43:30 +00:00
|
|
|
<Show when={person() !== null && person()!.person_classroom_id === undefined}>
|
|
|
|
<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>
|
2023-09-30 16:16:20 +00:00
|
|
|
</Show>
|
2023-09-26 21:13:30 +00:00
|
|
|
|
2023-09-21 22:07:18 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-09-22 17:03:25 +00:00
|
|
|
|
2023-09-21 21:06:31 +00:00
|
|
|
|
2023-10-03 16:43:30 +00:00
|
|
|
function ClassroomUser(props: {person: Person, onLink: (classroom_id: number) => void,}) {
|
2023-09-26 21:13:30 +00:00
|
|
|
const [active, setActive] = createSignal<TabType>("Vinculate");
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<FilledCard class="border border-c-outline overflow-hidden">
|
|
|
|
<h2 class="p-3 font-bold text-xl">
|
|
|
|
Persona no vinculada:
|
|
|
|
</h2>
|
|
|
|
<ClassroomTabs active={active()} setActive={setActive} />
|
|
|
|
|
|
|
|
<div class="bg-c-surface">
|
|
|
|
<Show when={active() === "Vinculate"}>
|
2023-09-30 16:16:20 +00:00
|
|
|
<ClassroomVinculation
|
|
|
|
person_surname={`${props.person.person_paternal_surname} ${props.person.person_maternal_surname}`}
|
2023-10-03 16:43:30 +00:00
|
|
|
personId={props.person.person_id}
|
|
|
|
onLink={props.onLink}
|
2023-09-30 16:16:20 +00:00
|
|
|
/>
|
2023-09-26 21:13:30 +00:00
|
|
|
</Show>
|
|
|
|
<Show when={active() === "Create"}>
|
|
|
|
<ClassroomUserCreation />
|
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</FilledCard>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-10-02 16:22:12 +00:00
|
|
|
type Status = "Init" | "Ok" | "Loading" | "Error";
|
2023-10-03 16:43:30 +00:00
|
|
|
function ClassroomVinculation(props: {person_surname: string, personId: number, onLink: (classroom_id: number) => void,}) {
|
2023-09-30 16:16:20 +00:00
|
|
|
const [classroomUsers, setClassroomUsers] = createSignal<ClassroomRegistrationUser[]>([]);
|
2023-10-02 16:22:12 +00:00
|
|
|
const [error, setError] = createSignal("");
|
|
|
|
const [status, setStatus] = createSignal<Status>("Init");
|
2023-09-30 16:16:20 +00:00
|
|
|
|
|
|
|
const loadUsers = async() => {
|
2023-10-02 16:22:12 +00:00
|
|
|
setStatus("Loading");
|
2023-09-30 16:16:20 +00:00
|
|
|
const response = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/classroom/users/${encodeURIComponent(props.person_surname)}`);
|
2023-10-02 16:22:12 +00:00
|
|
|
const json: JsonResult<Array<ClassroomRegistrationUser>> = await response.json();
|
2023-09-30 16:16:20 +00:00
|
|
|
|
|
|
|
if (response.ok) {
|
2023-10-02 16:22:12 +00:00
|
|
|
setClassroomUsers(json.Ok);
|
|
|
|
setStatus("Ok");
|
2023-09-30 16:16:20 +00:00
|
|
|
} else {
|
|
|
|
console.error("Error loading users", json);
|
2023-10-02 16:22:12 +00:00
|
|
|
setError(json.Err.reason);
|
|
|
|
setStatus("Error");
|
2023-09-30 16:16:20 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
onMount(loadUsers);
|
|
|
|
|
2023-09-21 21:06:31 +00:00
|
|
|
return (
|
|
|
|
<div>
|
2023-09-26 21:13:30 +00:00
|
|
|
<p class="py-2 px-4">
|
|
|
|
Vincule un usuario existente:
|
|
|
|
</p>
|
2023-10-02 16:22:12 +00:00
|
|
|
|
|
|
|
<Show when={status() === "Loading"}>
|
|
|
|
<div class="text-center h-12 scale-150">
|
|
|
|
<SpinnerGapIcon class="animate-spin" fill="var(--c-primary)" />
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
<Show when={status() === "Ok"}>
|
|
|
|
<Show when={classroomUsers().length === 0}>
|
|
|
|
<div class="px-4 pb-2">
|
|
|
|
<div class="text-center pt-6 pb-4">
|
|
|
|
<QuestionIcon class="scale-[200%]" fill="var(--c-outline)" />
|
|
|
|
</div>
|
|
|
|
<p>No se encontraron usuarios en el aula virtual.</p>
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
<For each={classroomUsers()}>
|
2023-10-03 16:43:30 +00:00
|
|
|
{(u) => (
|
|
|
|
<ClassroomSingleUser
|
|
|
|
user={u}
|
|
|
|
personId={props.personId}
|
|
|
|
onLink={props.onLink}
|
|
|
|
/>
|
|
|
|
)}
|
2023-10-02 16:22:12 +00:00
|
|
|
</For>
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
<Show when={status() === "Error"}>
|
|
|
|
<div class="px-4 pb-2 text-c-error">
|
|
|
|
<div class="text-center pt-6 pb-4">
|
|
|
|
<XcircleIcon class="scale-[200%]" fill="var(--c-error)" />
|
|
|
|
</div>
|
|
|
|
<p>Error buscando usuarios: {error()}.</p>
|
|
|
|
</div>
|
|
|
|
</Show>
|
2023-09-26 21:13:30 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-10-03 16:43:30 +00:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-09-26 21:13:30 +00:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
class="hover:bg-c-surface-variant hover:text-c-on-surface-variant transition-colors
|
|
|
|
grid grid-cols-[auto_3rem] gap-4"
|
|
|
|
>
|
|
|
|
<div class="pl-4 py-2">
|
2023-10-02 16:22:12 +00:00
|
|
|
{props.user.name} {props.user.surname}
|
2023-09-26 21:13:30 +00:00
|
|
|
<br />
|
|
|
|
<div class="grid grid-cols-[auto_10rem]">
|
|
|
|
<span class="font-mono">
|
2023-10-02 16:22:12 +00:00
|
|
|
{props.user.username}
|
2023-09-26 21:13:30 +00:00
|
|
|
</span>
|
|
|
|
<div>
|
|
|
|
registrado:
|
|
|
|
<span class="font-mono">
|
2023-10-02 16:22:12 +00:00
|
|
|
??/??/????
|
2023-09-26 21:13:30 +00:00
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<button
|
|
|
|
title="Vincular usuario"
|
|
|
|
class="border-2 border-c-transparent hover:border-c-primary transition-colors rounded"
|
2023-10-03 16:43:30 +00:00
|
|
|
onclick={linkUser}
|
|
|
|
disabled={status() === LoadingStatus.Loading}
|
2023-09-26 21:13:30 +00:00
|
|
|
>
|
|
|
|
<LinkIcon fill="var(--c-primary)" />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ClassroomTabs(props: {active: TabType, setActive: (v: TabType) => void}) {
|
|
|
|
const presetsClasses = () => ((props.active === "Vinculate") ? "font-bold border-c-primary" : "border-c-transparent");
|
|
|
|
const manualClasses = () => ((props.active === "Create") ? "font-bold border-c-primary" : "border-c-transparent");
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div class="grid grid-cols-2">
|
|
|
|
<button
|
|
|
|
class={`py-2 border-b-4 ${presetsClasses()}`}
|
|
|
|
onclick={() => props.setActive("Vinculate")}
|
|
|
|
>
|
|
|
|
Vincular
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
class={`py-2 border-b-4 ${manualClasses()}`}
|
|
|
|
onclick={() => props.setActive("Create")}
|
|
|
|
>
|
|
|
|
Crear
|
|
|
|
</button>
|
2023-09-21 21:06:31 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|