From 227b6920529624e27a1f4c01c49b53f188e4ada4 Mon Sep 17 00:00:00 2001 From: xeovalyte Date: Sun, 21 Jul 2024 21:04:18 +0200 Subject: [PATCH] Started on members upload --- assets/tailwind.css | 536 ++++++++++++++++++++++++++++++++ src/components.rs | 1 + src/components/admin.rs | 1 + src/components/admin/members.rs | 78 +++++ src/main.rs | 5 +- src/util/model/member.rs | 18 +- 6 files changed, 636 insertions(+), 3 deletions(-) create mode 100644 src/components/admin.rs create mode 100644 src/components/admin/members.rs diff --git a/assets/tailwind.css b/assets/tailwind.css index 0f43beb..97cd06d 100644 --- a/assets/tailwind.css +++ b/assets/tailwind.css @@ -860,6 +860,16 @@ html { opacity: 1; } + .btm-nav > *.disabled:hover, + .btm-nav > *[disabled]:hover { + pointer-events: none; + --tw-border-opacity: 0; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-bg-opacity: 0.1; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + --tw-text-opacity: 0.2; + } + .btn:hover { --tw-border-opacity: 1; border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity))); @@ -904,6 +914,18 @@ html { } } + .btn-outline.btn-primary:hover { + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); + } + + @supports (color: color-mix(in oklab, black, black)) { + .btn-outline.btn-primary:hover { + background-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); + border-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); + } + } + .btn-disabled:hover, .btn[disabled]:hover, .btn:disabled:hover { @@ -932,6 +954,60 @@ html { display: none; } +.file-input { + height: 3rem; + flex-shrink: 1; + padding-inline-end: 1rem; + font-size: 1rem; + line-height: 2; + line-height: 1.5rem; + overflow: hidden; + border-radius: var(--rounded-btn, 0.5rem); + border-width: 1px; + border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity))); + --tw-border-opacity: 0; + --tw-bg-opacity: 1; + background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity))); +} + +.file-input::file-selector-button { + margin-inline-end: 1rem; + display: inline-flex; + height: 100%; + flex-shrink: 0; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + flex-wrap: wrap; + align-items: center; + justify-content: center; + padding-left: 1rem; + padding-right: 1rem; + text-align: center; + font-size: 0.875rem; + line-height: 1.25rem; + line-height: 1em; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); + transition-duration: 200ms; + border-style: solid; + --tw-border-opacity: 1; + border-color: var(--fallback-n,oklch(var(--n)/var(--tw-border-opacity))); + --tw-bg-opacity: 1; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + font-weight: 600; + text-transform: uppercase; + --tw-text-opacity: 1; + color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity))); + text-decoration-line: none; + border-width: var(--border-btn, 1px); + animation: button-pop var(--animation-btn, 0.25s) ease-out; +} + .input { flex-shrink: 1; -webkit-appearance: none; @@ -957,12 +1033,77 @@ html { margin-inline-end: -1rem; } +.join { + display: inline-flex; + align-items: stretch; + border-radius: var(--rounded-btn, 0.5rem); +} + +.join :where(.join-item) { + border-start-end-radius: 0; + border-end-end-radius: 0; + border-end-start-radius: 0; + border-start-start-radius: 0; +} + +.join .join-item:not(:first-child):not(:last-child), + .join *:not(:first-child):not(:last-child) .join-item { + border-start-end-radius: 0; + border-end-end-radius: 0; + border-end-start-radius: 0; + border-start-start-radius: 0; +} + +.join .join-item:first-child:not(:last-child), + .join *:first-child:not(:last-child) .join-item { + border-start-end-radius: 0; + border-end-end-radius: 0; +} + .join .dropdown .join-item:first-child:not(:last-child), .join *:first-child:not(:last-child) .dropdown .join-item { border-start-end-radius: inherit; border-end-end-radius: inherit; } +.join :where(.join-item:first-child:not(:last-child)), + .join :where(*:first-child:not(:last-child) .join-item) { + border-end-start-radius: inherit; + border-start-start-radius: inherit; +} + +.join .join-item:last-child:not(:first-child), + .join *:last-child:not(:first-child) .join-item { + border-end-start-radius: 0; + border-start-start-radius: 0; +} + +.join :where(.join-item:last-child:not(:first-child)), + .join :where(*:last-child:not(:first-child) .join-item) { + border-start-end-radius: inherit; + border-end-end-radius: inherit; +} + +@supports not selector(:has(*)) { + :where(.join *) { + border-radius: inherit; + } +} + +@supports selector(:has(*)) { + :where(.join *:has(.join-item)) { + border-radius: inherit; + } +} + +.menu li.disabled { + cursor: not-allowed; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + color: var(--fallback-bc,oklch(var(--bc)/0.3)); +} + .navbar { display: flex; align-items: center; @@ -976,6 +1117,36 @@ html { align-items: center; } +.steps { + display: inline-grid; + grid-auto-flow: column; + overflow: hidden; + overflow-x: auto; + counter-reset: step; + grid-auto-columns: 1fr; +} + +.steps .step { + display: grid; + grid-template-columns: repeat(1, minmax(0, 1fr)); + grid-template-columns: auto; + grid-template-rows: repeat(2, minmax(0, 1fr)); + grid-template-rows: 40px 1fr; + place-items: center; + text-align: center; + min-width: 4rem; +} + +.btm-nav > *.disabled, + .btm-nav > *[disabled] { + pointer-events: none; + --tw-border-opacity: 0; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-bg-opacity: 0.1; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + --tw-text-opacity: 0.2; +} + @media (prefers-reduced-motion: no-preference) { .btn { animation: button-pop var(--animation-btn, 0.25s) ease-out; @@ -993,6 +1164,17 @@ html { background-color: var(--btn-color, var(--fallback-b2)); border-color: var(--btn-color, var(--fallback-b2)); } + + .btn-primary { + --btn-color: var(--fallback-p); + } +} + +@supports (color: color-mix(in oklab, black, black)) { + .btn-outline.btn-primary.btn-active { + background-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); + border-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); + } } .btn:focus-visible { @@ -1001,6 +1183,18 @@ html { outline-offset: 2px; } +.btn-primary { + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); + outline-color: var(--fallback-p,oklch(var(--p)/1)); +} + +@supports (color: oklch(0% 0 0)) { + .btn-primary { + --btn-color: var(--p); + } +} + .btn.glass { --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; @@ -1029,6 +1223,16 @@ html { background-color: var(--fallback-bc,oklch(var(--bc)/0.2)); } +.btn-outline.btn-primary { + --tw-text-opacity: 1; + color: var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity))); +} + +.btn-outline.btn-primary.btn-active { + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); +} + .btn.btn-disabled, .btn[disabled], .btn:disabled { @@ -1089,6 +1293,46 @@ html { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } +.file-input-bordered { + --tw-border-opacity: 0.2; +} + +.file-input:focus { + outline-style: solid; + outline-width: 2px; + outline-offset: 2px; + outline-color: var(--fallback-bc,oklch(var(--bc)/0.2)); +} + +.file-input-disabled, + .file-input[disabled] { + cursor: not-allowed; + --tw-border-opacity: 1; + border-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity))); + --tw-bg-opacity: 1; + background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity))); + --tw-text-opacity: 0.2; +} + +.file-input-disabled::-moz-placeholder, .file-input[disabled]::-moz-placeholder { + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity))); + --tw-placeholder-opacity: 0.2; +} + +.file-input-disabled::placeholder, + .file-input[disabled]::placeholder { + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity))); + --tw-placeholder-opacity: 0.2; +} + +.file-input-disabled::file-selector-button, .file-input[disabled]::file-selector-button { + --tw-border-opacity: 0; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-bg-opacity: 0.2; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + --tw-text-opacity: 0.2; +} + .input input { --tw-bg-opacity: 1; background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); @@ -1147,6 +1391,12 @@ html { text-align: inherit; } +.join > :where(*:not(:first-child)) { + margin-top: 0px; + margin-bottom: 0px; + margin-inline-start: -1px; +} + .join > :where(*:not(:first-child)):is(.btn) { margin-inline-start: calc(var(--border-btn) * -1); } @@ -1250,6 +1500,128 @@ html { } } +.steps .step:before { + top: 0px; + grid-column-start: 1; + grid-row-start: 1; + height: 0.5rem; + width: 100%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + --tw-bg-opacity: 1; + background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); + content: ""; + margin-inline-start: -100%; +} + +.steps .step:after { + content: counter(step); + counter-increment: step; + z-index: 1; + position: relative; + grid-column-start: 1; + grid-row-start: 1; + display: grid; + height: 2rem; + width: 2rem; + place-items: center; + place-self: center; + border-radius: 9999px; + --tw-bg-opacity: 1; + background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); +} + +.steps .step:first-child:before { + content: none; +} + +.steps .step[data-content]:after { + content: attr(data-content); +} + +.steps .step-neutral + .step-neutral:before, + .steps .step-neutral:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity))); +} + +.steps .step-primary + .step-primary:before, + .steps .step-primary:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); +} + +.steps .step-secondary + .step-secondary:before, + .steps .step-secondary:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); +} + +.steps .step-accent + .step-accent:before, + .steps .step-accent:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity))); +} + +.steps .step-info + .step-info:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity))); +} + +.steps .step-info:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity))); +} + +.steps .step-success + .step-success:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity))); +} + +.steps .step-success:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity))); +} + +.steps .step-warning + .step-warning:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity))); +} + +.steps .step-warning:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity))); +} + +.steps .step-error + .step-error:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity))); +} + +.steps .step-error:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity))); +} + @keyframes toast-pop { 0% { transform: scale(0.9); @@ -1262,6 +1634,10 @@ html { } } +.btn-wide { + width: 16rem; +} + .btn-square:where(.btn-xs) { height: 1.5rem; width: 1.5rem; @@ -1286,22 +1662,148 @@ html { padding: 0px; } +.join.join-vertical { + flex-direction: column; +} + +.join.join-vertical .join-item:first-child:not(:last-child), + .join.join-vertical *:first-child:not(:last-child) .join-item { + border-end-start-radius: 0; + border-end-end-radius: 0; + border-start-start-radius: inherit; + border-start-end-radius: inherit; +} + +.join.join-vertical .join-item:last-child:not(:first-child), + .join.join-vertical *:last-child:not(:first-child) .join-item { + border-start-start-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: inherit; + border-end-end-radius: inherit; +} + +.join.join-horizontal { + flex-direction: row; +} + +.join.join-horizontal .join-item:first-child:not(:last-child), + .join.join-horizontal *:first-child:not(:last-child) .join-item { + border-end-end-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: inherit; + border-start-start-radius: inherit; +} + +.join.join-horizontal .join-item:last-child:not(:first-child), + .join.join-horizontal *:last-child:not(:first-child) .join-item { + border-end-start-radius: 0; + border-start-start-radius: 0; + border-end-end-radius: inherit; + border-start-end-radius: inherit; +} + +.steps-horizontal .step { + display: grid; + grid-template-columns: repeat(1, minmax(0, 1fr)); + grid-template-rows: repeat(2, minmax(0, 1fr)); + place-items: center; + text-align: center; +} + +.steps-vertical .step { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-rows: repeat(1, minmax(0, 1fr)); +} + +.join.join-vertical > :where(*:not(:first-child)) { + margin-left: 0px; + margin-right: 0px; + margin-top: -1px; +} + .join.join-vertical > :where(*:not(:first-child)):is(.btn) { margin-top: calc(var(--border-btn) * -1); } +.join.join-horizontal > :where(*:not(:first-child)) { + margin-top: 0px; + margin-bottom: 0px; + margin-inline-start: -1px; +} + .join.join-horizontal > :where(*:not(:first-child)):is(.btn) { margin-inline-start: calc(var(--border-btn) * -1); } +.steps-horizontal .step { + grid-template-rows: 40px 1fr; + grid-template-columns: auto; + min-width: 4rem; +} + +.steps-horizontal .step:before { + height: 0.5rem; + width: 100%; + --tw-translate-x: 0px; + --tw-translate-y: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + content: ""; + margin-inline-start: -100%; +} + +.steps-horizontal .step:where([dir="rtl"], [dir="rtl"] *):before { + --tw-translate-x: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.steps-vertical .step { + gap: 0.5rem; + grid-template-columns: 40px 1fr; + grid-template-rows: auto; + min-height: 4rem; + justify-items: start; +} + +.steps-vertical .step:before { + height: 100%; + width: 0.5rem; + --tw-translate-x: -50%; + --tw-translate-y: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + margin-inline-start: 50%; +} + +.steps-vertical .step:where([dir="rtl"], [dir="rtl"] *):before { + --tw-translate-x: 50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .static { position: static; } +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.mt-16 { + margin-top: 4rem; +} + +.mt-5 { + margin-top: 1.25rem; +} + .flex { display: flex; } +.contents { + display: contents; +} + .size-8 { width: 2rem; height: 2rem; @@ -1324,6 +1826,14 @@ html { min-height: 4rem; } +.w-full { + width: 100%; +} + +.max-w-md { + max-width: 28rem; +} + .flex-1 { flex: 1 1 0%; } @@ -1344,6 +1854,10 @@ html { align-items: center; } +.justify-center { + justify-content: center; +} + .justify-around { justify-content: space-around; } @@ -1356,11 +1870,20 @@ html { gap: 0.5rem; } +.overflow-y-auto { + overflow-y: auto; +} + .bg-base-200 { --tw-bg-opacity: 1; background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity))); } +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + .px-3 { padding-left: 0.75rem; padding-right: 0.75rem; @@ -1371,6 +1894,15 @@ html { padding-bottom: 0.25rem; } +.py-10 { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + +.pb-16 { + padding-bottom: 4rem; +} + .text-xl { font-size: 1.25rem; line-height: 1.75rem; @@ -1388,3 +1920,7 @@ html { --tw-text-opacity: 1; color: var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity))); } + +.filter { + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} diff --git a/src/components.rs b/src/components.rs index 2544120..c4dc47e 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1,2 +1,3 @@ +pub mod admin; pub mod home; pub mod layout; diff --git a/src/components/admin.rs b/src/components/admin.rs new file mode 100644 index 0000000..424919c --- /dev/null +++ b/src/components/admin.rs @@ -0,0 +1 @@ +pub mod members; diff --git a/src/components/admin/members.rs b/src/components/admin/members.rs new file mode 100644 index 0000000..5b73ff8 --- /dev/null +++ b/src/components/admin/members.rs @@ -0,0 +1,78 @@ +use dioxus::prelude::{dioxus_elements::FileEngine, *}; +use std::sync::Arc; + +#[derive(Debug)] +struct UploadedFile { + name: String, + contents: String, +} + +#[component] +pub fn Migration() -> Element { + let mut file_uploaded = use_signal(|| None); + + let read_files = move |file_engine: Arc| async move { + let files = file_engine.files(); + for file_name in &files { + if let Some(contents) = file_engine.read_file_to_string(file_name).await { + file_uploaded.set(Some(UploadedFile { + name: file_name.clone(), + contents, + })); + } + } + }; + + let upload_files = move |evt: FormEvent| async move { + if let Some(file_engine) = evt.files() { + read_files(file_engine).await; + } + }; + + let sumbit = move |_evt: FormEvent| async move { + match &*file_uploaded.read() { + Some(file) => { + if let Ok(_response) = upload_members_list(file.contents.clone()).await { + tracing::info!("Loaded!!"); + } + } + None => tracing::info!("File doesn't exists"), + } + }; + rsx! { + div { + class: "flex flex-col items-center justify-center h-full py-10", + ul { + class: "steps pb-16", + li { class: "step step-primary", "Uploaden" }, + li { class: "step", "Controleren" }, + li { class: "step", "Klaar" }, + } + form { + class: "flex flex-col items-center w-full h-full max-w-md mx-auto px-2", + onsubmit: sumbit, + h2 { class: "text-xl", "Selecteer het ledenbestand" }, + input { + r#type: "file", + class: "file-input file-input-bordered w-full mt-16", + accept: ".csv", + multiple: false, + autocomplete: false, + onchange: upload_files, + } + input { + r#type: "submit", + class: "btn btn-primary btn-wide mt-5", + disabled: file_uploaded.read().is_none(), + value: "Uploaden" + } + } + } + } +} + +#[server] +async fn upload_members_list(input: String) -> Result { + tracing::info!("Getting members..."); + Ok("Whoo".to_string()) +} diff --git a/src/main.rs b/src/main.rs index 7b16633..e551fb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use dioxus::prelude::*; use tracing::{info, Level}; // Use routes +use components::admin::members::Migration; use components::home::Home; #[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)] @@ -14,6 +15,8 @@ pub enum Route { #[layout(Wrapper)] #[route("/")] Home {}, + #[route("/admin/members/migration")] + Migration {}, } const _TAILWIND_URL: &str = manganis::mg!(file("assets/tailwind.css")); @@ -60,7 +63,7 @@ fn Wrapper() -> Element { rsx! { components::layout::topbar::Topbar {} main { - class: "h-full", + class: "h-full overflow-y-auto", Outlet:: {} } components::layout::navbar::Navbar {} diff --git a/src/util/model/member.rs b/src/util/model/member.rs index 28148b7..e693dba 100644 --- a/src/util/model/member.rs +++ b/src/util/model/member.rs @@ -1,8 +1,11 @@ +#[cfg(feature = "server")] +use crate::util::surrealdb::DB; +use serde::Deserialize; use std::collections::BTreeSet; mod migration; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct Member { id: String, name: Name, @@ -12,8 +15,19 @@ pub struct Member { registration_token: Option, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct Name { first: String, full: String, } + +#[cfg(feature = "server")] +impl Member { + pub async fn fetch_all() -> Result, surrealdb::Error> { + let mut res = DB.query("SELECT type::string(id) as id, name, hours, groups, diploma, registration_token FROM member").await?; + + let members: Vec = res.take(0)?; + + Ok(members) + } +}