Skip to content

Commit

Permalink
prenova strani "Vsi uporabniki"
Browse files Browse the repository at this point in the history
  • Loading branch information
mytja committed Nov 2, 2024
1 parent 8b0fce3 commit 9aa61af
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 150 deletions.
98 changes: 98 additions & 0 deletions src/Admin/UserSection.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import LayoutGrid, { Cell } from '@smui/layout-grid';
import {formatDate} from "date-fns";
import Card from "@smui/card";
import type {UserJSON} from "../typescript-definitions/tsdef";
import {Icon} from "@smui/common";
import {Link} from "svelte-routing";
import Select, {Option} from "@smui/select";
import {baseurl, saveBlob} from "../constants";
import Button from "@smui/button";
export let users: UserJSON[];
export let callUpdate: Function;
const choices = ["unverified", "student", "parent", "teacher", "food organizer", "school psychologist", "principal assistant", "principal"];
const translationMap: Record<string, string> = {
"unverified": "Nepreverjen",
"student": "Učenec",
"parent": "Starš",
"teacher": "Učitelj",
"food organizer": "Organizator prehrane",
"school psychologist": "Šolski psiholog",
"principal assistant": "Pomočnik ravnatelja",
"principal": "Ravnatelj",
}
</script>

<LayoutGrid>
{#each users as user, i}
<Cell span={3}>
<div style="padding: 5px;">
<Card variant="outlined" padded>
<span class="sameline">
<span class="inline"><b>{user.Name} {user.Surname}</b></span>
{#if user.IsMissingInfo}
<Icon class="inline material-icons" style="float: right; color: yellow; font-size: 25px; font-weight: bold;">warning</Icon>
{/if}
{#if user.IsLocked}
<Icon class="inline material-icons" style="float: right; font-size: 25px; font-weight: bold;">lock</Icon>
{/if}
</span>
<br>
{user.Email}
<br>
<Link to="/user/{user.ID}">Dodatne informacije o uporabniku</Link>
<br>
<Select bind:value={user.Role} label="Izberite vlogo v sistemu">
{#each choices as choice}
<Option value={choice} on:click={async () => {
let fd = new FormData();
fd.append("role", choice);

await fetch(`${baseurl}/user/role/update/${user.ID}`, {
credentials: "include",
body: fd,
method: "PATCH"
})
callUpdate();
}}>{translationMap[choice]}</Option>
{/each}
</Select>
<p/>
<div class="sameline">
<Button on:click={async () => {
await fetch(`${baseurl}/user/lock_unlock/${user.ID}`, {credentials: "include", method: "PATCH"});
callUpdate();
}} variant="{user.IsLocked ? 'raised' : 'outlined'}">
<Icon class="material-icons">{#if user.IsLocked}lock_open{:else}lock{/if}</Icon>
{#if user.IsLocked}Odkleni uporabnika{:else}Zakleni uporabnika{/if}
</Button>
</div>
<div class="sameline">
<Button on:click={async () => {
let response = await fetch(`${baseurl}/user/get/password_reset/${user.ID}`, {credentials: "include"})
let blob = await response.blob()
await saveBlob(blob)
}} variant="outlined">
<Icon class="material-icons">download</Icon>
Ponastavi geslo
</Button>
</div>
<div style="height: 25px">

</div>
<div class="sameline">
<Button on:click={async () => {
await fetch(`${baseurl}/user/delete/${user.ID}`, {credentials: "include", method: "DELETE"})
callUpdate();
}} variant="outlined">
<Icon class="material-icons">delete</Icon>
Izbriši uporabnika
</Button>
</div>
</Card>
</div>
</Cell>
{/each}
</LayoutGrid>
190 changes: 79 additions & 111 deletions src/Admin/Users.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,135 +7,103 @@
import Icon from '@smui/textfield/icon';
import Button from "@smui/button";
import { navigate } from "svelte-routing";
import FormField from "@smui/form-field";
import Switch from "@smui/switch";
import {onMount} from "svelte";
import UserSection from "./UserSection.svelte";
import type {UserJSON} from "../typescript-definitions/tsdef";
let loaded: boolean = false;
let items = [];
let principalId = undefined;
let unverified: UserJSON[] = [];
let students: UserJSON[] = [];
let parents: UserJSON[] = [];
let teachers: UserJSON[] = [];
let foodOrganizers: UserJSON[] = [];
let psychologists: UserJSON[] = [];
let assistants: UserJSON[] = [];
let principal: UserJSON | undefined = undefined;
let admin: UserJSON | undefined = undefined;
async function loadThings() {
loaded = false;
let response = await fetch(`${baseurl}/users/get`, {credentials: "include"})
let json = await response.json();
items = json["data"];
loaded = true;
for (let i in items) {
let item = items[i]
if (item.Role === "principal") {
principalId = item.ID;
break
principal = undefined;
admin = undefined;
unverified = [];
students = [];
parents = [];
teachers = [];
foodOrganizers = [];
psychologists = [];
assistants = [];
for (let i of json["data"]) {
let item = i
if (item.Role === "unverified") {
unverified.push(i)
} else if (item.Role === "student") {
students.push(i)
} else if (item.Role === "parent") {
parents.push(i)
} else if (item.Role === "teacher") {
teachers.push(i)
} else if (item.Role === "food organizer") {
foodOrganizers.push(i)
} else if (item.Role === "school psychologist") {
psychologists.push(i);
} else if (item.Role === "principal assistant") {
assistants.push(i);
} else if (item.Role === "principal") {
principal = i;
} else if (item.Role === "admin") {
admin = i;
}
}
unverified.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
students.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
parents.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
teachers.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
foodOrganizers.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
psychologists.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
assistants.sort((a, b) => `${a.Surname} ${a.Name}`.localeCompare(`${b.Surname} ${b.Name}`))
}
const choices = ["unverified", "student", "parent", "teacher", "food organizer", "school psychologist", "principal assistant", "principal"];
import { navigate } from "svelte-routing";
import FormField from "@smui/form-field";
import Switch from "@smui/switch";
import {onMount} from "svelte";
const role = localStorage.getItem("role");
onMount(loadThings);
</script>

<DataTable table$aria-label="User list" style="width: 100%;">
<Head>
<Row>
<Cell numeric>ID</Cell>
<Cell style="width: 100%;">Name</Cell>
<Cell>Email</Cell>
<Cell>Change role</Cell>
<Cell>Lock user</Cell>
<Cell>Reset password</Cell>
<Cell>Delete user</Cell>
<Cell>View</Cell>
</Row>
</Head>
<Body>
{#each items as item}
<Row>
<Cell numeric>{item["ID"]}</Cell>
<Cell>{item["Name"]}</Cell>
<Cell>{item["Email"]}</Cell>
<Cell>
{#if localStorage.getItem("userId") !== item["ID"]}
<SegmentedButton segments={choices} let:segment singleSelect on:change={async (e) => {
e.stopPropagation();
let fd = new FormData();
fd.append("role", e.detail.segmentId);
principalId = undefined;

await fetch(`${baseurl}/user/role/update/${item["ID"]}`, {
credentials: "include",
body: fd,
method: "PATCH"
})
await loadThings()
}} bind:selected="{item['Role']}">
{#if
(localStorage.getItem("role") === "principal assistant" && !(segment === "principal" || segment === "principal assistant")) ||
(localStorage.getItem("role") === "principal" && !(segment === "principal")) ||
(localStorage.getItem("role") === "admin")
}
{#if !(segment === "principal" && principalId !== undefined && principalId !== item.ID)}
<Segment {segment}>
<Label>{segment}</Label>
</Segment>
{/if}
{/if}
</SegmentedButton>
{/if}
</Cell>
<Cell>
{#if localStorage.getItem("email") !== item["Email"]}
<FormField>
<Switch bind:checked={item["IsLocked"]} on:click={async (e) => {
e.stopPropagation();
await fetch(`${baseurl}/user/lock_unlock/${item["ID"]}`, {credentials: "include", method: "PATCH"});
await loadThings();
}} />
</FormField>
{/if}
</Cell>
<Cell>
{#if localStorage.getItem("email") !== item["Email"]}
<IconButton class="material-icons" on:click={async (e) => {
e.stopPropagation();
let response = await fetch(`${baseurl}/user/get/password_reset/${item["ID"]}`, {credentials: "include"})
let blob = await response.blob()
await saveBlob(blob)
}}>download</IconButton>
{/if}
</Cell>
<Cell>
{#if localStorage.getItem("email") !== item["Email"]}
<IconButton class="material-icons" on:click={async (e) => {
e.stopPropagation();
await fetch(`${baseurl}/user/delete/${item["ID"]}`, {
credentials: "include",
method: "DELETE"
})
await loadThings()
}}>delete</IconButton>
{/if}
</Cell>
<Cell>
<IconButton class="material-icons" on:click={(e) => {
e.stopPropagation();
navigate(`/user/${item["ID"]}`)
}}>info</IconButton>
</Cell>
</Row>
{/each}
</Body>

<LinearProgress
indeterminate
bind:closed={loaded}
aria-label="Data is being loaded..."
slot="progress"
/>
</DataTable>
<h2>Nepreverjeni uporabniki</h2>
<UserSection users={unverified} callUpdate={loadThings} />

<h2>Učenci</h2>
<UserSection users={students} callUpdate={loadThings} />

<h2>Starši</h2>
<UserSection users={parents} callUpdate={loadThings} />

<h2>Učitelji</h2>
<UserSection users={teachers} callUpdate={loadThings} />

<h2>Organizatorji prehrane</h2>
<UserSection users={foodOrganizers} callUpdate={loadThings} />

<h2>Šolski psihologi</h2>
<UserSection users={psychologists} callUpdate={loadThings} />

<h2>Pomočniki ravnatelja</h2>
<UserSection users={assistants} callUpdate={loadThings} />

<h2>Ravnatelj</h2>
<UserSection users={principal === undefined ? [] : [principal]} callUpdate={loadThings}/>

<h2>Administrator</h2>
<UserSection users={admin === undefined ? [] : [admin]} />

<p/>
<Button on:click={() => navigate("/register")}>
<Icon class="material-icons">group_add</Icon>
Expand Down
59 changes: 30 additions & 29 deletions src/User.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,35 @@
getMyChildren();
</script>

<Textfield bind:value={name} label="Ime" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite ime - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={surname} label="Priimek" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite priimek - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={email} label="Elektronski naslov" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite elektronski naslov - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={phoneNumber} label="Telefonska številka" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite telefonsko številko - bodite zelo pozorni</HelperText>
</Textfield>
<Select bind:value={gender} label="Izberite spol" variant="outlined" on:MDCSelect:change={async () => await patchUser()}>
<Option value=""/>
<Option value="male">Moški</Option>
<Option value="female">Ženski</Option>
</Select>
<p/>
{#if role === "student" || role === "parent"}
<Textfield bind:value={permanentAddress} label="Stalni naslov" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite stalni naslov - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={temporaryAddress} label="Začasni naslov" style="width: 100%;" on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite začasni naslov - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={taxNumber} label="Davčna številka" style="width: 100%;" on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite davčno številko - bodite zelo pozorni</HelperText>
</Textfield>
{/if}
{#if role === "student"}
<Textfield bind:value={birthCertificateNumber} label="Številka matičnega lista" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite številko matičnega lista - bodite zelo pozorni</HelperText>
Expand All @@ -144,7 +173,7 @@
<HelperText slot="helper">Vpišite datum rojstva - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={emso} label="EMŠO" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite EMŠO - bodite zelo pozorni</HelperText>
<HelperText slot="helper">Vpišite EMŠO (avtomatično preverja veljavnost glede na spol)</HelperText>
</Textfield>
<Textfield bind:value={citizenship} label="Državljanstvo" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite državljanstvo (npr. slovensko) - bodite zelo pozorni</HelperText>
Expand All @@ -153,34 +182,6 @@
<HelperText slot="helper">Vpišite predhodno pridobljeno izobrazbo (npr. OŠ Primer, 2013-2022)</HelperText>
</Textfield>
{/if}
{#if role === "student" || role === "parent"}
<Textfield bind:value={permanentAddress} label="Stalni naslov" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite stalni naslov - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={temporaryAddress} label="Začasni naslov" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite začasni naslov - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={taxNumber} label="Država rojstva" style="width: 100%;" on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite davčno številko - bodite zelo pozorni</HelperText>
</Textfield>
{/if}
<Textfield bind:value={name} label="Ime" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite ime - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={surname} label="Priimek" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite priimek - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={email} label="Elektronski naslov" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite elektronski naslov - bodite zelo pozorni</HelperText>
</Textfield>
<Textfield bind:value={phoneNumber} label="Telefonska številka" style="width: 100%;" required on:change={async () => await patchUser()}>
<HelperText slot="helper">Vpišite telefonsko številko - bodite zelo pozorni</HelperText>
</Textfield>
<Select bind:value={gender} label="Izberite spol" variant="outlined" on:MDCSelect:change={async () => await patchUser()}>
<Option value=""/>
<Option value="male">Moški</Option>
<Option value="female">Ženski</Option>
</Select>

{#if role === "student"}
<h2>Dodaj učenca v razred:</h2>
Expand Down
Loading

0 comments on commit 9aa61af

Please sign in to comment.