[FE] Improve UI for classroom
This commit is contained in:
parent
4d70e7c428
commit
525c72a9f6
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
target
|
||||
.env
|
||||
aulavirtual
|
||||
scraps
|
||||
|
@ -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:
|
||||
<span class="font-mono">
|
||||
26/05/2023
|
||||
??/??/????
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
16
frontend/src/icons/QuestionIcon.tsx
Normal file
16
frontend/src/icons/QuestionIcon.tsx
Normal 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>
|
||||
);
|
||||
}
|
16
frontend/src/icons/SpinnerGapIcon.tsx
Normal file
16
frontend/src/icons/SpinnerGapIcon.tsx
Normal 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>
|
||||
);
|
||||
}
|
16
frontend/src/icons/XCircleIcon.tsx
Normal file
16
frontend/src/icons/XCircleIcon.tsx
Normal 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>
|
||||
);
|
||||
}
|
6
frontend/src/types/JsonResult.ts
Normal file
6
frontend/src/types/JsonResult.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export type JsonResult<T> = {
|
||||
Ok: T,
|
||||
Err: {
|
||||
reason: string
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user