eeg_certs/frontend/src/OnlineClassroom/index.tsx

177 lines
6.1 KiB
TypeScript
Raw Normal View History

2023-09-30 16:16:20 +00:00
import { For, Show, createSignal, onMount } from "solid-js";
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-09-26 21:13:30 +00:00
type TabType = "Vinculate" | "Create";
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-09-30 16:16:20 +00:00
<Show when={person() !== null && !person()!.person_classroom_id}>
<ClassroomUser person={person()!} />
</Show>
2023-09-26 21:13:30 +00:00
2023-09-21 22:07:18 +00:00
</div>
</div>
);
}
2023-09-26 21:13:30 +00:00
function ClassroomUser(props: {person: Person}) {
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-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-09-30 16:16:20 +00:00
function ClassroomVinculation(props: {person_surname: string}) {
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);
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()}>
{(u) => <ClassroomSingleUser user={u} />}
</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-02 16:22:12 +00:00
function ClassroomSingleUser(props: {user: ClassroomRegistrationUser}) {
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:&nbsp;
<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"
>
<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>
</div>
);
}