Support registering & displaying preview certs
This commit is contained in:
parent
6bd0acc03e
commit
e8e5835236
@ -1,6 +1,5 @@
|
||||
use crate::db;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::Row;
|
||||
|
||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
||||
pub struct CustomLabel {
|
||||
|
@ -16,6 +16,7 @@ pub struct RegisterCreate {
|
||||
date: String,
|
||||
/// Foreign key to the custom_label table
|
||||
custom_label: String,
|
||||
is_preview: bool,
|
||||
}
|
||||
|
||||
impl RegisterCreate {
|
||||
@ -57,7 +58,7 @@ impl RegisterCreate {
|
||||
current_date,
|
||||
self.date,
|
||||
custom_label_id,
|
||||
false,
|
||||
self.is_preview,
|
||||
self.person_id,
|
||||
self.course_id
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ export function ManualRegistration(props: {
|
||||
|
||||
const [selectedCourseId, seSelectedCourseId] = createSignal<number | null>(null);
|
||||
const [customLabel, setCustomLabel] = createSignal("");
|
||||
const [isPreview, setIsPreview] = createSignal(false);
|
||||
|
||||
let datePicker: HTMLInputElement | undefined;
|
||||
|
||||
@ -68,6 +69,7 @@ export function ManualRegistration(props: {
|
||||
courseId: subject,
|
||||
date,
|
||||
customLabel: customLabel(),
|
||||
is_preview: isPreview(),
|
||||
};
|
||||
|
||||
props.onAdd(data);
|
||||
@ -86,7 +88,7 @@ export function ManualRegistration(props: {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="my-4 grid grid-cols-[9.5rem_auto] gap-2">
|
||||
<div class="mt-4 mb-2 grid grid-cols-[9.5rem_auto] gap-2">
|
||||
<div class="relative">
|
||||
<input
|
||||
ref={datePicker}
|
||||
@ -108,7 +110,16 @@ export function ManualRegistration(props: {
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input
|
||||
oninput={(ev) => setIsPreview(ev.target.checked)}
|
||||
checked={isPreview()}
|
||||
type="checkbox"
|
||||
name="is_preview"
|
||||
id="manual-is-preview"
|
||||
/>
|
||||
<label class="px-2 py-2 select-none" for="manual-is-preview">Cert sin firmas</label>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
|
||||
|
@ -46,6 +46,7 @@ export function RegisterPresets(props: {
|
||||
}) {
|
||||
let datePicker: HTMLInputElement | undefined;
|
||||
const [selectedPreset, setSelectedPreset] = createSignal<PresetName>("None");
|
||||
const [isPreview, setIsPreview] = createSignal(false);
|
||||
const [error, setError] = createSignal("");
|
||||
const presets = genPresets();
|
||||
|
||||
@ -86,6 +87,7 @@ export function RegisterPresets(props: {
|
||||
courseId,
|
||||
date: dateYYYYMMDD,
|
||||
customLabel: "",
|
||||
is_preview: isPreview(),
|
||||
});
|
||||
|
||||
// Substract current date for the next course
|
||||
@ -112,7 +114,7 @@ export function RegisterPresets(props: {
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-4">
|
||||
<div class="mt-4 mb-2">
|
||||
<div class="relative">
|
||||
<input
|
||||
ref={datePicker}
|
||||
@ -123,6 +125,16 @@ export function RegisterPresets(props: {
|
||||
<label for="create-date" class="absolute -top-2 left-2 text-xs bg-c-surface px-1">Fecha</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
oninput={(ev) => setIsPreview(ev.target.checked)}
|
||||
checked={isPreview()}
|
||||
type="checkbox"
|
||||
name="is_preview"
|
||||
id="preset-is-preview"
|
||||
/>
|
||||
<label class="px-2 py-2 select-none" for="preset-is-preview">Cert sin firmas</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
class="bg-c-primary text-c-on-primary px-4 py-2 rounded-full cursor-pointer
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { FilledCard } from "../../components/FilledCard";
|
||||
import { For, createSignal } from "solid-js";
|
||||
import { For, Show, createSignal } from "solid-js";
|
||||
import { XIcon } from "../../icons/XIcon";
|
||||
import { allCourses } from "../../utils/allCourses";
|
||||
import { RegisterBatchCreate } from "../../types/Register";
|
||||
import { RegistrationPreview } from ".";
|
||||
import { loadCustomLabels } from "../../utils/allCustomLabels";
|
||||
import { FileDashedIcon } from "../../icons/FileDashedIcon";
|
||||
|
||||
|
||||
function isoDateToLocalDate(date: string): string {
|
||||
@ -24,11 +25,12 @@ export function RegisterPreview(props: {selections: Array<RegistrationPreview>,
|
||||
|
||||
await wait(2000);
|
||||
|
||||
const registers: RegisterBatchCreate = props.selections.map(({courseId, date, customLabel}) => ({
|
||||
const registers: RegisterBatchCreate = props.selections.map(({courseId, date, customLabel, is_preview}) => ({
|
||||
person_id: props.personId!,
|
||||
course_id: courseId,
|
||||
date,
|
||||
custom_label: customLabel,
|
||||
is_preview,
|
||||
}));
|
||||
|
||||
const result = await createRegisters(registers);
|
||||
@ -50,12 +52,13 @@ export function RegisterPreview(props: {selections: Array<RegistrationPreview>,
|
||||
<h2 class="p-4 font-bold text-xl">Confirmar registro</h2>
|
||||
<div class="bg-c-surface p-4">
|
||||
<For each={props.selections}>
|
||||
{({courseId, date, customLabel}) => (
|
||||
{({courseId, date, customLabel, is_preview}) => (
|
||||
<Register
|
||||
courseId={courseId}
|
||||
date={date}
|
||||
onDelete={props.onDelete}
|
||||
customLabel={customLabel}
|
||||
isPreview={is_preview}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
@ -74,23 +77,38 @@ export function RegisterPreview(props: {selections: Array<RegistrationPreview>,
|
||||
);
|
||||
}
|
||||
|
||||
function Register(props: {courseId: number, date: string, customLabel: string, onDelete: (v: number) => void}) {
|
||||
function Register(props: {
|
||||
courseId: number,
|
||||
date: string,
|
||||
customLabel: string,
|
||||
onDelete: (v: number) => void,
|
||||
isPreview: boolean,
|
||||
}) {
|
||||
const courseName = () => {
|
||||
const courses = allCourses();
|
||||
return courses.find((course) => course.course_id === props.courseId)?.course_name ?? `Curso invalido! (${props.courseId})`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-[auto_4rem_1.5rem] py-1 px-2 rounded-md border border-c-outline my-1">
|
||||
{courseName()}
|
||||
<span class="font-mono">{isoDateToLocalDate(props.date)}</span>
|
||||
<div class="grid grid-cols-[auto_3rem_1.5rem] py-1 px-2 rounded-md border border-c-outline my-1">
|
||||
<span title={props.isPreview ? "Sin firmas" : ""}>
|
||||
<Show when={props.isPreview}>
|
||||
<FileDashedIcon size={16} class="pr-2" fill="var(--c-on-surface)" />
|
||||
</Show>
|
||||
{courseName()}
|
||||
</span>
|
||||
<span class="font-mono">
|
||||
{isoDateToLocalDate(props.date)}
|
||||
</span>
|
||||
<button
|
||||
class="hover:bg-c-surface-variant rounded-md"
|
||||
onclick={() => props.onDelete(props.courseId)}
|
||||
>
|
||||
<XIcon fill="var(--c-on-surface)" />
|
||||
</button>
|
||||
{props.customLabel}
|
||||
<span>
|
||||
{props.customLabel}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ export type RegistrationPreview = {
|
||||
courseId: number,
|
||||
date: string,
|
||||
customLabel: string,
|
||||
is_preview: boolean,
|
||||
}
|
||||
|
||||
export function NewRegister(props: {
|
||||
@ -32,7 +33,7 @@ export function NewRegister(props: {
|
||||
|
||||
<RegisterTabs active={active()} setActive={setActive} />
|
||||
|
||||
<div class="bg-c-surface p-4 h-[22rem]">
|
||||
<div class="bg-c-surface p-4 h-[23rem]">
|
||||
<Show when={active() === "Presets"}>
|
||||
<RegisterPresets
|
||||
onAdd={(v) => setSelections((x) => [...x, v])}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { For, Show, createEffect, createMemo, createSignal } from "solid-js";
|
||||
import { For, Match, Show, createEffect, createMemo, createSignal } from "solid-js";
|
||||
import { Person } from "../../types/Person";
|
||||
import { Register } from "../../types/Register";
|
||||
import { courseMap } from "../../utils/allCourses";
|
||||
@ -180,18 +180,6 @@ function RegisterEl(props: {register: Register, person: Person, onClick: () => v
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-[11rem_1.5rem_1.25rem] border border-c-outline rounded-md">
|
||||
{/*
|
||||
<div class=" w-12 inline-block">
|
||||
<Show when={generateable()}>
|
||||
<button
|
||||
onclick={genCert}
|
||||
class="rounded-full bg-c-primary-container hover:bg-c-primary transition-colors h-12 w-12"
|
||||
>
|
||||
<DownloadIcon fill="var(--c-on-primary-container)" />
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
*/}
|
||||
<div class="p-1 border-r border-c-outline-50 align-middle">
|
||||
<p
|
||||
class="font-bold overflow-hidden whitespace-nowrap"
|
||||
@ -205,10 +193,21 @@ function RegisterEl(props: {register: Register, person: Person, onClick: () => v
|
||||
</span>
|
||||
|
||||
</p>
|
||||
<p class="font-mono text-sm">
|
||||
{displayDate()}
|
||||
-
|
||||
{props.register.register_code}
|
||||
<p class="text-sm">
|
||||
<span class="font-mono">
|
||||
{displayDate()}
|
||||
</span>
|
||||
|
||||
<Show when={props.register.register_is_preview}>
|
||||
<span class="text-c-error font-bold select-none">
|
||||
sin firmas
|
||||
</span>
|
||||
</Show>
|
||||
<Show when={!props.register.register_is_preview}>
|
||||
<span class="font-mono">
|
||||
- {props.register.register_code}
|
||||
</span>
|
||||
</Show>
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
15
frontend/src/icons/FileDashedIcon.tsx
Normal file
15
frontend/src/icons/FileDashedIcon.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
export function FileDashedIcon(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="M80,224a8,8,0,0,1-8,8H56a16,16,0,0,1-16-16V184a8,8,0,0,1,16,0v32H72A8,8,0,0,1,80,224ZM216,88v48a8,8,0,0,1-16,0V96H152a8,8,0,0,1-8-8V40H120a8,8,0,0,1,0-16h32a8,8,0,0,1,5.66,2.34l56,56A8,8,0,0,1,216,88Zm-56-8h28.69L160,51.31ZM80,24H56A16,16,0,0,0,40,40V64a8,8,0,0,0,16,0V40H80a8,8,0,0,0,0-16ZM208,168a8,8,0,0,0-8,8v40h-8a8,8,0,0,0,0,16h8a16,16,0,0,0,16-16V176A8,8,0,0,0,208,168ZM48,152a8,8,0,0,0,8-8V104a8,8,0,0,0-16,0v40A8,8,0,0,0,48,152Zm104,64H112a8,8,0,0,0,0,16h40a8,8,0,0,0,0-16Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
@ -9,6 +9,7 @@ export type RegisterBatchCreate = Array<{
|
||||
* Value of the custom label
|
||||
*/
|
||||
custom_label: string,
|
||||
is_preview: boolean,
|
||||
}>
|
||||
|
||||
export type Register = {
|
||||
|
Loading…
Reference in New Issue
Block a user