[FE] Improve UI for classroom

master
Araozu 2023-10-02 11:22:12 -05:00
parent 4d70e7c428
commit 525c72a9f6
6 changed files with 101 additions and 10 deletions

1
backend/.gitignore vendored
View File

@ -1,3 +1,4 @@
target
.env
aulavirtual
scraps

View File

@ -5,6 +5,10 @@ import { FilledCard } from "../components/FilledCard";
import { LinkIcon } from "../icons/LinkIcon";
import { ClassroomUserCreation } from "./ClassroomUserCreation";
import { ClassroomRegistrationUser } from "../types/ClassroomRegistrationUser";
import { SpinnerGapIcon } from "../icons/SpinnerGapIcon";
import { QuestionIcon } from "../icons/QuestionIcon";
import { JsonResult } from "../types/JsonResult";
import { XcircleIcon } from "../icons/XCircleIcon";
type TabType = "Vinculate" | "Create";
@ -54,19 +58,25 @@ function ClassroomUser(props: {person: Person}) {
);
}
type Status = "Init" | "Ok" | "Loading" | "Error";
function ClassroomVinculation(props: {person_surname: string}) {
const [classroomUsers, setClassroomUsers] = createSignal<ClassroomRegistrationUser[]>([]);
const [error, setError] = createSignal("");
const [status, setStatus] = createSignal<Status>("Init");
const loadUsers = async() => {
setStatus("Loading");
const response = await fetch(`${import.meta.env.VITE_BACKEND_URL}/api/classroom/users/${encodeURIComponent(props.person_surname)}`);
const json = await response.json();
const json: JsonResult<Array<ClassroomRegistrationUser>> = await response.json();
if (response.ok) {
setClassroomUsers(json);
setClassroomUsers(json.Ok);
setStatus("Ok");
} else {
console.error("Error loading users", json);
setError(json.Err.reason);
setStatus("Error");
}
};
onMount(loadUsers);
@ -76,32 +86,58 @@ function ClassroomVinculation(props: {person_surname: string}) {
<p class="py-2 px-4">
Vincule un usuario existente:
</p>
<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()}>
{(_) => <ClassroomSingleUser />}
{(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>
</div>
);
}
function ClassroomSingleUser() {
function ClassroomSingleUser(props: {user: ClassroomRegistrationUser}) {
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">
NOMBRE NOMBRE APELLIDO APELLIDO
{props.user.name} {props.user.surname}
<br />
<div class="grid grid-cols-[auto_10rem]">
<span class="font-mono">
NNAPELLA
{props.user.username}
</span>
<div>
registrado:&nbsp;
<span class="font-mono">
26/05/2023
??/??/????
</span>
</div>
</div>

View File

@ -0,0 +1,16 @@
export function QuestionIcon(props: {fill: string, size?: number, class?: string}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`inline-block w-6 ${props.class}`}
width={props.size ?? 32}
height={props.size ?? 32}
fill={props.fill}
viewBox="0 0 256 256"
>
<path d="M140,180a12,12,0,1,1-12-12A12,12,0,0,1,140,180ZM128,72c-22.06,0-40,16.15-40,36v4a8,8,0,0,0,16,0v-4c0-11,10.77-20,24-20s24,9,24,20-10.77,20-24,20a8,8,0,0,0-8,8v8a8,8,0,0,0,16,0v-.72c18.24-3.35,32-17.9,32-35.28C168,88.15,150.06,72,128,72Zm104,56A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z" />
</svg>
);
}

View File

@ -0,0 +1,16 @@
export function SpinnerGapIcon(props: {fill: string, size?: number, class?: string}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`inline-block w-6 ${props.class}`}
width={props.size ?? 32}
height={props.size ?? 32}
fill={props.fill}
viewBox="0 0 256 256"
>
<path d="M136,32V64a8,8,0,0,1-16,0V32a8,8,0,0,1,16,0Zm37.25,58.75a8,8,0,0,0,5.66-2.35l22.63-22.62a8,8,0,0,0-11.32-11.32L167.6,77.09a8,8,0,0,0,5.65,13.66ZM224,120H192a8,8,0,0,0,0,16h32a8,8,0,0,0,0-16Zm-45.09,47.6a8,8,0,0,0-11.31,11.31l22.62,22.63a8,8,0,0,0,11.32-11.32ZM128,184a8,8,0,0,0-8,8v32a8,8,0,0,0,16,0V192A8,8,0,0,0,128,184ZM77.09,167.6,54.46,190.22a8,8,0,0,0,11.32,11.32L88.4,178.91A8,8,0,0,0,77.09,167.6ZM72,128a8,8,0,0,0-8-8H32a8,8,0,0,0,0,16H64A8,8,0,0,0,72,128ZM65.78,54.46A8,8,0,0,0,54.46,65.78L77.09,88.4A8,8,0,0,0,88.4,77.09Z" />
</svg>
);
}

View File

@ -0,0 +1,16 @@
export function XcircleIcon(props: {fill: string, size?: number, class?: string}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`inline-block w-6 ${props.class}`}
width={props.size ?? 32}
height={props.size ?? 32}
fill={props.fill}
viewBox="0 0 256 256"
>
<path d="M165.66,101.66,139.31,128l26.35,26.34a8,8,0,0,1-11.32,11.32L128,139.31l-26.34,26.35a8,8,0,0,1-11.32-11.32L116.69,128,90.34,101.66a8,8,0,0,1,11.32-11.32L128,116.69l26.34-26.35a8,8,0,0,1,11.32,11.32ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z" />
</svg>
);
}

View File

@ -0,0 +1,6 @@
export type JsonResult<T> = {
Ok: T,
Err: {
reason: string
}
};