[FE] UI for online classroom user
This commit is contained in:
parent
62e7b1a29c
commit
abd9f789d3
@ -10,7 +10,8 @@ CREATE TABLE person (
|
||||
person_dni VARCHAR(8) NOT NULL,
|
||||
person_names VARCHAR(50) NOT NULL,
|
||||
person_paternal_surname VARCHAR(30) NOT NULL,
|
||||
person_maternal_surname VARCHAR(30) NOT NULL
|
||||
person_maternal_surname VARCHAR(30) NOT NULL,
|
||||
person_classroom_id INTEGER DEFAULT -1
|
||||
);
|
||||
|
||||
CREATE TABLE course (
|
||||
|
31
frontend/src/OnlineClassroom/ClassroomUserCreation.tsx
Normal file
31
frontend/src/OnlineClassroom/ClassroomUserCreation.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { FilledButton } from "../components/FilledButton";
|
||||
import { UserPlusIcon } from "../icons/UserPlusIcon";
|
||||
import { MaterialInput } from "../components/MaterialInput";
|
||||
|
||||
export function ClassroomUserCreation() {
|
||||
const [email, setEmail] = createSignal("yuli.palo.apaza@gmail.com");
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
|
||||
return (
|
||||
<div class="px-4 pb-4">
|
||||
<p class="py-2">
|
||||
O cree un nuevo usuario:
|
||||
</p>
|
||||
|
||||
<form>
|
||||
<MaterialInput
|
||||
resourceName="Correo"
|
||||
value={email()}
|
||||
setValue={setEmail}
|
||||
disabled={loading()}
|
||||
/>
|
||||
</form>
|
||||
|
||||
<FilledButton class="ml-2">
|
||||
<UserPlusIcon fill="var(--c-on-primary)" class="mr-2 relative scale-150" size={16} />
|
||||
Crear usuario
|
||||
</FilledButton>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -34,7 +34,7 @@ export function ClassroomConection() {
|
||||
<Switch fallback={"Desconectado"}>
|
||||
<Match when={status() === "connected"}>
|
||||
<span class="bg-c-success text-c-on-success px-2 rounded select-none font-mono">
|
||||
Conectado
|
||||
Ok
|
||||
</span>
|
||||
</Match>
|
||||
<Match when={status() === "connecting"}>
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { Show, createSignal } from "solid-js";
|
||||
import { Search } from "../certs/Search";
|
||||
import { Person } from "../types/Person";
|
||||
import { ClassroomConection } from "./ConnectionStatus";
|
||||
import { FilledCard } from "../components/FilledCard";
|
||||
import { LinkIcon } from "../icons/LinkIcon";
|
||||
import { ClassroomUserCreation } from "./ClassroomUserCreation";
|
||||
|
||||
type TabType = "Vinculate" | "Create";
|
||||
|
||||
export function OnlineClassroom() {
|
||||
const [person, setPerson] = createSignal<Person | null>(null);
|
||||
@ -10,10 +14,9 @@ export function OnlineClassroom() {
|
||||
<div class="grid grid-cols-[16rem_25rem_1fr]">
|
||||
<Search setPerson={setPerson} />
|
||||
<div>
|
||||
<ClassroomConection />
|
||||
<Show when={person()}>
|
||||
<ClassroomUsers person={person()!} />
|
||||
</Show>
|
||||
|
||||
<ClassroomUser person={person()!} />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -21,12 +24,96 @@ export function OnlineClassroom() {
|
||||
|
||||
|
||||
|
||||
function ClassroomUsers(props: {person: Person}) {
|
||||
function ClassroomUser(props: {person: Person}) {
|
||||
const [active, setActive] = createSignal<TabType>("Vinculate");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 class="text-xl">
|
||||
Usuarios para {props.person.person_names}:
|
||||
</h2>
|
||||
<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"}>
|
||||
<ClassroomVinculation />
|
||||
</Show>
|
||||
<Show when={active() === "Create"}>
|
||||
<ClassroomUserCreation />
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
</FilledCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ClassroomVinculation() {
|
||||
return (
|
||||
<div>
|
||||
<p class="py-2 px-4">
|
||||
Vincule un usuario existente:
|
||||
</p>
|
||||
<ClassroomSingleUser />
|
||||
<ClassroomSingleUser />
|
||||
<ClassroomSingleUser />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ClassroomSingleUser() {
|
||||
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
|
||||
<br />
|
||||
<div class="grid grid-cols-[auto_10rem]">
|
||||
<span class="font-mono">
|
||||
NNAPELLA
|
||||
</span>
|
||||
<div>
|
||||
registrado:
|
||||
<span class="font-mono">
|
||||
26/05/2023
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { MaterialInput } from "../../components/MaterialInput";
|
||||
|
||||
export function PersonRegister(props: {dni: string, onRegister: () => void}) {
|
||||
const [paternalSurname, setPaternalSurname] = createSignal("");
|
||||
@ -48,22 +49,22 @@ export function PersonRegister(props: {dni: string, onRegister: () => void}) {
|
||||
}}
|
||||
>
|
||||
<MaterialInput
|
||||
name="Apellido paterno"
|
||||
resourceName="Apellido paterno"
|
||||
value={paternalSurname()}
|
||||
setValue={(v) => setPaternalSurname(v.toUpperCase())}
|
||||
loading={loading()}
|
||||
disabled={loading()}
|
||||
/>
|
||||
<MaterialInput
|
||||
name="Apellido materno"
|
||||
resourceName="Apellido materno"
|
||||
value={maternalSurname()}
|
||||
setValue={(v) => setMaternalSurname(v.toUpperCase())}
|
||||
loading={loading()}
|
||||
disabled={loading()}
|
||||
/>
|
||||
<MaterialInput
|
||||
name="Nombres"
|
||||
resourceName="Nombres"
|
||||
value={names()}
|
||||
setValue={(v) => setNames(v.toUpperCase())}
|
||||
loading={loading()}
|
||||
disabled={loading()}
|
||||
/>
|
||||
|
||||
<button
|
||||
@ -77,35 +78,4 @@ export function PersonRegister(props: {dni: string, onRegister: () => void}) {
|
||||
);
|
||||
}
|
||||
|
||||
function MaterialInput(props: {
|
||||
name: string,
|
||||
loading: boolean,
|
||||
value: string,
|
||||
setValue: (v: string) => void,
|
||||
}) {
|
||||
let inputElement: HTMLInputElement | undefined;
|
||||
|
||||
return (
|
||||
<div class="relative my-6">
|
||||
<input
|
||||
ref={inputElement}
|
||||
id="search-dni"
|
||||
class="bg-c-background text-c-on-background border-c-outline border-2 rounded px-2 py-1 w-full
|
||||
invalid:border-c-error invalid:text-c-error
|
||||
focus:border-c-primary outline-none font-mono
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
type="text"
|
||||
placeholder={props.name}
|
||||
value={props.value}
|
||||
required
|
||||
onInput={(e) => props.setValue(e.target.value)}
|
||||
disabled={props.loading}
|
||||
/>
|
||||
|
||||
|
||||
<label for="search-dni" class="absolute -top-2 left-2 text-xs bg-c-surface px-1 select-none">
|
||||
{props.name}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export function Dialog(props: {onClose: () => void, children: Children, class?:
|
||||
});
|
||||
|
||||
return (
|
||||
<div class={`modal transition-colors ${positionClasses()}`}>
|
||||
<div class={`modal transition-colors bg-c-background ${positionClasses()}`}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
16
frontend/src/components/FilledButton.tsx
Normal file
16
frontend/src/components/FilledButton.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { JSX } from "solid-js";
|
||||
|
||||
export function FilledButton(props: {
|
||||
children?: Array<JSX.Element> | JSX.Element,
|
||||
class?: string,
|
||||
type?: "button" | "input",
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
class={`bg-c-primary text-c-on-primary px-4 py-2 rounded-full cursor-pointer mt-4
|
||||
disabled:opacity-50 disabled:cursor-not-allowed ${props.class}`}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
}
|
32
frontend/src/components/MaterialInput.tsx
Normal file
32
frontend/src/components/MaterialInput.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
export function MaterialInput(props: {
|
||||
resourceName: string,
|
||||
disabled: boolean,
|
||||
value: string,
|
||||
setValue: (v: string) => void,
|
||||
}) {
|
||||
let inputElement: HTMLInputElement | undefined;
|
||||
|
||||
return (
|
||||
<div class="relative my-6">
|
||||
<input
|
||||
ref={inputElement}
|
||||
id="search-dni"
|
||||
class="bg-c-background text-c-on-background border-c-outline border-2 rounded px-2 py-1 w-full
|
||||
invalid:border-c-error invalid:text-c-error
|
||||
focus:border-c-primary outline-none font-mono
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
type="text"
|
||||
placeholder={props.resourceName}
|
||||
value={props.value}
|
||||
required
|
||||
onInput={(e) => props.setValue(e.target.value)}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
|
||||
|
||||
<label for="search-dni" class="absolute -top-2 left-2 text-xs bg-c-surface px-1 select-none">
|
||||
{props.resourceName}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
16
frontend/src/components/TonalButton.tsx
Normal file
16
frontend/src/components/TonalButton.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import { JSX } from "solid-js";
|
||||
|
||||
export function TonalButton(props: {
|
||||
children?: Array<JSX.Element> | JSX.Element,
|
||||
class?: string,
|
||||
type?: "button" | "input",
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
class="bg-c-surface-variant text-c-on-surface-variant px-4 py-2 rounded-full cursor-pointer mt-4
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
}
|
15
frontend/src/icons/LinkIcon.tsx
Normal file
15
frontend/src/icons/LinkIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
export function LinkIcon(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="M137.54,186.36a8,8,0,0,1,0,11.31l-9.94,10A56,56,0,0,1,48.38,128.4L72.5,104.28A56,56,0,0,1,149.31,102a8,8,0,1,1-10.64,12,40,40,0,0,0-54.85,1.63L59.7,139.72a40,40,0,0,0,56.58,56.58l9.94-9.94A8,8,0,0,1,137.54,186.36Zm70.08-138a56.08,56.08,0,0,0-79.22,0l-9.94,9.95a8,8,0,0,0,11.32,11.31l9.94-9.94a40,40,0,0,1,56.58,56.58L172.18,140.4A40,40,0,0,1,117.33,142,8,8,0,1,0,106.69,154a56,56,0,0,0,76.81-2.26l24.12-24.12A56.08,56.08,0,0,0,207.62,48.38Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
15
frontend/src/icons/UserPlusIcon.tsx
Normal file
15
frontend/src/icons/UserPlusIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
export function UserPlusIcon(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="M256,136a8,8,0,0,1-8,8H232v16a8,8,0,0,1-16,0V144H200a8,8,0,0,1,0-16h16V112a8,8,0,0,1,16,0v16h16A8,8,0,0,1,256,136Zm-57.87,58.85a8,8,0,0,1-12.26,10.3C165.75,181.19,138.09,168,108,168s-57.75,13.19-77.87,37.15a8,8,0,0,1-12.25-10.3c14.94-17.78,33.52-30.41,54.17-37.17a68,68,0,1,1,71.9,0C164.6,164.44,183.18,177.07,198.13,194.85ZM108,152a52,52,0,1,0-52-52A52.06,52.06,0,0,0,108,152Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
@ -5,5 +5,6 @@ export type Person = {
|
||||
person_names: string
|
||||
person_paternal_surname: string
|
||||
person_maternal_surname: string
|
||||
person_classroom_id: string | undefined
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user