Archived
Private
Public Access
1
0

v0.0.1 (download not working)

This commit is contained in:
2023-04-30 20:50:39 +02:00
parent 227af36c05
commit 4f6c0a00be
116 changed files with 1460 additions and 356 deletions

View File

@@ -2,6 +2,8 @@ import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Userdata, AuthKeys} from "../entities/userdata";
import {firstValueFrom} from "rxjs";
import {environment} from "../../environments/environment";
import {Course} from "../entities/course";
@Injectable({
providedIn: 'root',
@@ -10,7 +12,7 @@ export class IServService {
public userdata?: Userdata;
public keys?: AuthKeys;
public backend: string = "http://localhost:5273";
public backend: string = environment.backend;
public courseNames: {[id: string]: string} = {
["Bi"]: "Biologie",
@@ -32,6 +34,14 @@ export class IServService {
["Sf"]: "Seminarfach",
["DS"]: "Darstellendes Spiel",
};
public colors: {name: string; val: string}[] = [
{name: "Blau", val: "primary"},
{name: "Hellblau", val: "secondary"},
{name: "Lila", val: "tertiary"},
{name: "Grün", val: "success"},
{name: "Gelb", val: "warning"},
{name: "Rot", val: "danger"}
];
constructor(private client: HttpClient) {
const data = localStorage.getItem("userdata");
@@ -83,7 +93,13 @@ export class IServService {
}
}
public async getCoursesAndClass(groups?: string[]): Promise<{class: string, courses: string[]}> {
public async getCoursesAndClass(groups?: string[]): Promise<{class: string, courses: Course[]}> {
if (localStorage.getItem("courses") && localStorage.getItem("class")) {
const courses = JSON.parse(localStorage.getItem("courses")) as Course[];
const className = localStorage.getItem("class");
return {courses, class: className};
}
if (groups == undefined) {
groups = await this.getGroups();
}
@@ -99,13 +115,37 @@ export class IServService {
result.class = grades[0].replace("Jahrgang ", "").toUpperCase();
}
}
localStorage.setItem("class", result.class);
for (let group of groups) {
if (!group.includes(".") || !group.toLowerCase().startsWith("q")) continue;
result.courses.push(group.split(".")[1]);
}
return result;
if (result.class.startsWith("Q")) {
const courses: Course[] = [];
for (let course of result.courses) {
const short = course.substring(1, 3);
const name = this.courseNames[short];
if (name == undefined) continue;
courses.push({
id: course,
short: short.toUpperCase(),
name: name,
color: this.colors[Math.floor(Math.random() * this.colors.length)].val
});
}
courses.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
localStorage.setItem("courses", JSON.stringify(courses));
return {class: result.class, courses};
}
return {class: result.class, courses: []};
}
}

View File

@@ -16,7 +16,6 @@ export class AppComponent {
{ title: 'Übersicht', url: '/home', icon: 'home' },
{ title: 'E-Mail', url: '/mails', icon: 'mail' },
{ title: 'Dateien', url: '/files', icon: 'folder' },
{ title: 'Aufgaben', url: '/tasks', icon: 'clipboard' },
{ title: 'Stundenplan', url: '/schedule', icon: 'grid' },
{ title: 'Vertretungsplan', url: '/substitution', icon: 'list' },
];

View File

@@ -23,12 +23,12 @@ export const routes: Routes = [
loadComponent: () => import('./pages/mails/mails.page').then( m => m.MailsPage)
},
{
path: 'substitution',
loadComponent: () => import('./pages/substitution/substitution.page').then( m => m.SubstitutionPage)
path: 'mails/:id',
loadComponent: () => import('./pages/mails/mails.page').then( m => m.MailsPage)
},
{
path: 'tasks',
loadComponent: () => import('./pages/tasks/tasks.page').then( m => m.TasksPage)
path: 'substitution',
loadComponent: () => import('./pages/substitution/substitution.page').then( m => m.SubstitutionPage)
},
{
path: 'schedule',

View File

@@ -0,0 +1,13 @@
<ion-card>
<ion-card-header>
<span
class="lesson-icon ion-text-center"
[style]="'--background: var(--ion-color-' + findCourse(lesson?.course)?.color + '); --foreground: var(--ion-color-' + findCourse(lesson?.course)?.color + '-contrast)'"
>
{{findCourse(lesson?.course)?.short || "PH"}}
</span>
</ion-card-header>
<ion-card-content class="ion-text-center">
<ion-label>{{lesson?.room || "&#10240; &#x2800;"}}</ion-label>
</ion-card-content>
</ion-card>

View File

@@ -0,0 +1,8 @@
ion-card {
margin: 10px 0 0;
width: 100%;
ion-card-header, ion-card-content {
padding: 7px;
}
}

View File

@@ -0,0 +1,25 @@
import {Component, Input} from '@angular/core';
import {IonicModule} from "@ionic/angular";
import {Course, Lesson} from "../../entities/course";
@Component({
selector: 'lesson',
templateUrl: './lesson.component.html',
styleUrls: ['./lesson.component.scss'],
imports: [
IonicModule
],
standalone: true
})
export class LessonComponent {
@Input('courses') courses: Course[];
@Input('lesson') lesson: Lesson;
public findCourse(id: string): Course {
for (let course of this.courses)
if (course.id == id) return course;
return undefined;
}
}

View File

@@ -0,0 +1,10 @@
<ion-item class="mail pointer">
<div>
<div>
<ion-icon ios="mail-unread-outline" md="mail-unread-sharp" *ngIf="!message.read" />
<ion-label>{{message.sender.displayName}}</ion-label>
<ion-label class="date">{{message.time.toLocaleDateString()}}</ion-label>
</div>
<ion-label class="subject">{{message.subject}}</ion-label>
</div>
</ion-item>

View File

@@ -0,0 +1,25 @@
.mail > div {
display: flex;
flex-direction: column;
gap: 7px;
margin-block: 15px;
width: 100%;
.subject, .date {
font-size: 15px;
}
& > div {
display: flex;
ion-icon {
margin-right: 5px;
align-self: center;
color: var(--ion-color-primary);
}
.date {
margin-left: auto;
}
}
}

View File

@@ -0,0 +1,20 @@
import {Component, Input, OnInit} from '@angular/core';
import {IonicModule} from "@ionic/angular";
import {MailContent} from "../../entities/mail";
import {NgIf} from "@angular/common";
@Component({
selector: 'mail',
templateUrl: './mail.component.html',
styleUrls: ['./mail.component.scss'],
imports: [
IonicModule,
NgIf
],
standalone: true
})
export class MailComponent {
@Input('mail') message: MailContent;
}

View File

@@ -0,0 +1,11 @@
<ion-card
class="subs {{subs?.type.replace(' ', '').replace('.', '')}}"
>
<ion-card-content>
<ion-label class="times">{{subs?.times.join(" - ")}}</ion-label>
<div>
<ion-label class="type">{{subs?.type}}</ion-label>
<ion-label class="desc" [innerHtml]="getDetails(subs)"></ion-label>
</div>
</ion-card-content>
</ion-card>

View File

@@ -0,0 +1,44 @@
.subs {
ion-card-content {
display: flex;
gap: 15px;
color: #FFF;
.times {
font-size: 25px;
line-height: 25px;
align-self: center;
}
div {
margin-left: auto;
display: flex;
flex-direction: column;
align-items: flex-end;
.type {
font-size: 18px;
}
}
}
&.Raumtausch {
--background: var(--ion-color-success-shade);
}
&.bittebeachten, &.stregulärem {
--background: var(--ion-color-tertiary-shade);
}
&.Vertretung {
--background: var(--ion-color-primary-shade);
}
&.Entfall, &.Stillarbeit {
--background: var(--ion-color-danger-shade);
}
&.Verlegung {
--background: var(--ion-color-warning-shade);
}
}

View File

@@ -0,0 +1,52 @@
import {Component, Input, OnInit} from '@angular/core';
import {Substitution} from "../../entities/substitution";
import {IonicModule} from "@ionic/angular";
@Component({
selector: 'substitution',
templateUrl: './substitution.component.html',
styleUrls: ['./substitution.component.scss'],
imports: [
IonicModule
],
standalone: true
})
export class SubstitutionComponent {
@Input('subs') subs: Substitution;
public getDetails(subs: Substitution): string {
if (subs.type == "bitte beachten") {
const desc = subs.description != "&nbsp;" ? ' - ' + subs.description : "";
let info = `${subs.lesson} (${subs.teacher}) in ${subs.room}`;
if (subs.lesson != subs.newLesson) {
info = `${subs.newLesson} (${subs.representative}) statt ${subs.lesson} (${subs.teacher}) in ${subs.room}`;
}
return info + desc;
}
switch (subs.type) {
case "Vertretung":
case "st. regulärem Unt.":
return `${subs.lesson} (${subs.representative} statt ${subs.teacher}) in ${subs.room}`;
case "Raumtausch":
return `${subs.lesson} (${subs.teacher}) in ${subs.room}`;
case "Entfall":
return `${subs.lesson} (${subs.teacher})`;
case "Stillarbeit":
return `${subs.lesson} (${subs.teacher}) in ${subs.room}`;
case "Verlegung":
return `${subs.newLesson} (${subs.representative}) statt ${subs.lesson} (${subs.teacher}) in ${subs.room}`;
default:
return subs.lesson + ' (' + subs.teacher + ') ' + subs.room;
}
}
}

View File

@@ -13,4 +13,64 @@
<ion-title size="large">Übersicht</ion-title>
</ion-toolbar>
</ion-header>
<ion-card>
<ion-card-header>
<ion-card-title>Willkommen {{iserv.userdata?.username}}</ion-card-title>
<ion-card-subtitle *ngIf="classData != undefined">
Du hast {{unreadMails?.length || 0}} ungelesene E-Mails<br>
<span>{{classData?.class.startsWith('Q') ? 'Jahrgang' : 'Klasse'}} {{classData?.class}}</span><br>
{{dayName}} der {{today?.toLocaleDateString()}}
</ion-card-subtitle>
</ion-card-header>
</ion-card>
<ion-card>
<ion-card-header>
<ion-card-title>Stundenplan</ion-card-title>
</ion-card-header>
<ion-card-content class="lesson-content">
<ion-card *ngIf="lessons == undefined && classData != undefined">
<ion-card-header>
<ion-card-subtitle>Kein Unterricht</ion-card-subtitle>
</ion-card-header>
</ion-card>
<div class="lesson-container">
<lesson *ngFor="let lesson of lessons" [lesson]="lesson" [courses]="classData.courses" />
</div>
</ion-card-content>
</ion-card>
<ion-card>
<ion-card-header>
<ion-card-title>Vertretungsplan</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-card *ngIf="subs?.length == 0 && subs != undefined">
<ion-card-header>
<ion-card-subtitle>Keine Vertretungen</ion-card-subtitle>
</ion-card-header>
</ion-card>
<substitution *ngFor="let sub of subs" [subs]="sub" />
</ion-card-content>
</ion-card>
<ion-card>
<ion-card-header>
<ion-card-title>Ungelesene E-Mails</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-list>
<ion-card *ngIf="unreadMails?.length == 0 && unreadMails != undefined">
<ion-card-header>
<ion-card-subtitle>Keine ungelesenen E-Mails</ion-card-subtitle>
</ion-card-header>
</ion-card>
<mail *ngFor="let mail of unreadMails" [mail]="mail" (click)="router.navigate(['mails/' + mail.id])" />
</ion-list>
</ion-card-content>
</ion-card>
</ion-content>

View File

@@ -1 +1,9 @@
.lesson-container {
display: flex;
flex-grow: 1;
gap: 8px;
}
.lesson-content {
overflow-x: scroll;
}

View File

@@ -2,18 +2,56 @@ import {Component, OnInit} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import {IServService} from "../../api/iserv.service";
import {MailService} from "../../api/mail.service";
import {MailContent} from "../../entities/mail";
import {UnitsService} from "../../api/units.service";
import {Substitution} from "../../entities/substitution";
import {SubstitutionComponent} from "../../components/substitution/substitution.component";
import {MailComponent} from "../../components/mail/mail.component";
import {Router} from "@angular/router";
import {Course, Lesson, Timetable} from "../../entities/course";
import {LessonComponent} from "../../components/lesson/lesson.component";
@Component({
selector: 'app-home',
templateUrl: './home.page.html',
styleUrls: ['./home.page.scss'],
standalone: true,
imports: [IonicModule, CommonModule, FormsModule]
imports: [IonicModule, CommonModule, FormsModule, SubstitutionComponent, MailComponent, LessonComponent]
})
export class HomePage implements OnInit {
ngOnInit() {
public unreadMails: MailContent[];
public today: Date;
public dayName: string;
public subs: Substitution[];
public classData: {class: string, courses: Course[]};
public lessons: Lesson[];
public constructor(public iserv: IServService, public mails: MailService, public units: UnitsService, public router: Router) {}
async ngOnInit() {
this.today = new Date();
this.dayName = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"][this.today.getDay()];
const scheduleDay = [undefined, "mon", "tue", "wed", "thu", "fri", undefined][this.today.getDay()];
const mailPromise = this.mails.getMails("INBOX", 0);
const classPromise = this.iserv.getCoursesAndClass();
const subsPromise = this.units.getSubstitutionPlan("today");
await Promise.all([mailPromise, classPromise, subsPromise]);
this.unreadMails = (await mailPromise).filter(mail => !mail.read);
this.classData = await classPromise;
this.subs = (await subsPromise).substitutions.filter(subs => subs.classes.includes(this.classData.class));
if (this.classData.class.startsWith("Q")) {
this.subs = this.subs.filter(subs => this.classData.courses.filter(course => course.id == subs.lesson).length > 0);
}
if (scheduleDay != undefined && localStorage.getItem("timetable")) {
this.lessons = (JSON.parse(localStorage.getItem("timetable")) as Timetable)[scheduleDay].filter(lesson => lesson != undefined);
}
}
}

View File

@@ -11,9 +11,11 @@
<ion-card-title>IServ Anmeldedaten</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-input label="E-Mail" type="email" #email/>
<ion-input label="Passwort" type="password" #password/>
<ion-button (click)="onLogin(email.value?.toString(), password.value?.toString())">Einloggen</ion-button>
<form (submit)="$event.preventDefault(); onLogin(email.value?.toString(), password.value?.toString())">
<ion-input label="E-Mail" type="email" #email/>
<ion-input label="Passwort" type="password" #password/>
<ion-button type="submit">Einloggen</ion-button>
</form>
</ion-card-content>
</ion-card>
</div>

View File

@@ -23,7 +23,9 @@ export class LoginPage implements OnInit {
if (email == undefined || password == undefined) return;
if (await this.iservApi.login(email, password)) {
await this.router.navigate(['home']);
setTimeout(async () => {
await this.router.navigate(['home']);
}, 500);
}else {
const alert = await this.alerts.create({
header: "Fehler",

View File

@@ -53,16 +53,7 @@
</ion-item>
<ion-list>
<ion-item *ngFor="let message of mails" class="mail pointer" (click)="selectMail(message, mailModal)">
<div>
<div>
<ion-icon ios="mail-unread-outline" md="mail-unread-sharp" *ngIf="!message.read" />
<ion-label>{{message.sender.displayName}}</ion-label>
<ion-label class="date">{{message.time.toLocaleDateString()}}</ion-label>
</div>
<ion-label class="subject">{{message.subject}}</ion-label>
</div>
</ion-item>
<mail *ngFor="let message of mails" [mail]="message" (click)="selectMail(message, mailModal)" />
</ion-list>
<ion-infinite-scroll (ionInfinite)="loadMore($event)">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
@@ -81,9 +72,9 @@
</ion-header>
<ion-content class="ion-padding current-mail">
<div class="header">
<ion-label class="subject">{{currentMail?.subject}}</ion-label>
<ion-label class="subject">{{currentMail?.subject}}</ion-label><br>
<ion-label class="time">{{currentMail?.time.toLocaleDateString()}}</ion-label>
<ion-list *ngIf="currentMail?.attachments?.length > 0">
<ion-list *ngIf="currentMail?.attachments?.length > 0" style="margin-top: 10px">
<ion-item *ngFor="let attachment of currentMail?.attachments" class="pointer" (click)="downloadAttachment(attachment, currentMail?.id)">
<ion-label>{{attachment}}</ion-label>
</ion-item>

View File

@@ -1,44 +1,3 @@
.mail > div {
display: flex;
flex-direction: column;
gap: 7px;
margin-block: 15px;
width: 100%;
.subject, .date {
font-size: 15px;
}
& > div {
display: flex;
ion-icon {
margin-right: 5px;
color: var(--ion-color-primary);
}
.date {
margin-left: auto;
}
}
}
.current-mail {
.header {
display: flex;
flex-direction: column;
gap: 10px;
.subject {
font-weight: bold;
}
.time {
font-size: 15px;
}
}
}
.new-email {
display: flex;
flex-direction: column;

View File

@@ -1,20 +1,22 @@
import {Component, OnInit} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {InfiniteScrollCustomEvent, IonicModule, IonModal, Platform, ToastController} from '@ionic/angular';
import {IonicModule, IonModal, Platform, ToastController} from '@ionic/angular';
import {MailService} from "../../api/mail.service";
import {MailContent, MailFolder} from "../../entities/mail";
import {marked} from "marked";
import {HttpDownloadProgressEvent, HttpEventType} from "@angular/common/http";
import {HttpEventType} from "@angular/common/http";
import {File} from "@awesome-cordova-plugins/file/ngx";
import {saveAs} from "file-saver";
import {MailComponent} from "../../components/mail/mail.component";
import {ActivatedRoute} from "@angular/router";
@Component({
selector: 'app-mails',
templateUrl: './mails.page.html',
styleUrls: ['./mails.page.scss'],
standalone: true,
imports: [IonicModule, CommonModule, FormsModule]
imports: [IonicModule, CommonModule, FormsModule, MailComponent]
})
export class MailsPage implements OnInit {
@@ -25,7 +27,9 @@ export class MailsPage implements OnInit {
private currentPage = 0;
private currentFolder: MailFolder;
constructor(private mail: MailService, private platform: Platform, private toasts: ToastController) { }
@ViewChild('mailModal') mailModal: IonModal;
constructor(private mail: MailService, private platform: Platform, private toasts: ToastController, private route: ActivatedRoute) { }
async ngOnInit() {
this.showLoading = true;
@@ -38,6 +42,14 @@ export class MailsPage implements OnInit {
this.currentFolder = this.folders.filter(folder => folder.name == "INBOX")[0];
this.showLoading = false;
this.route.params.subscribe((params: {id: string}) => {
if (params.id != undefined) {
const id = Number(params.id);
const email = this.mails.filter(mail => mail.id == id)[0];
this.selectMail(email, this.mailModal);
}
})
}
public async changeFolder(folder: MailFolder) {

View File

@@ -24,8 +24,8 @@
<ion-content class="ion-padding course-content">
<ion-item>
<ion-label position="stacked">Farbe</ion-label>
<ion-select aria-label="Farbe" interface="action-sheet" [value]="colors[0].val" #color>
<ion-select-option *ngFor="let color of colors" [value]="color.val">
<ion-select aria-label="Farbe" interface="action-sheet" [value]="iserv.colors[0].val" #color>
<ion-select-option *ngFor="let color of iserv.colors" [value]="color.val">
{{color.name}}
</ion-select-option>
</ion-select>
@@ -124,7 +124,7 @@
<ion-card *ngFor="let course of courses" (click)="onEditOrAdd(course)">
<ion-card-header>
<span
class="icon ion-text-center"
class="lesson-icon ion-text-center"
[style]="'--background: var(--ion-color-' + course.color + '); --foreground: var(--ion-color-' + course.color + '-contrast)'"
>
{{course.short}}
@@ -146,19 +146,7 @@
<ion-label *ngIf="day == 'thu'">Do</ion-label>
<ion-label *ngIf="day == 'fri'">Fr</ion-label>
<ion-card *ngFor="let lesson of timetable[day] | week; let i = index" [ngClass]="{'hide': lesson == undefined}" (click)="onEditOrAdd(undefined, {lesson, day, time: i})">
<ion-card-header>
<span
class="icon ion-text-center"
[style]="'--background: var(--ion-color-' + findCourse(lesson?.course)?.color + '); --foreground: var(--ion-color-' + findCourse(lesson?.course)?.color + '-contrast)'"
>
{{findCourse(lesson?.course)?.short || "&#10240; &#x2800;"}}
</span>
</ion-card-header>
<ion-card-content class="ion-text-center">
<ion-label>{{lesson?.room || "&#10240; &#x2800;"}}</ion-label>
</ion-card-content>
</ion-card>
<lesson *ngFor="let lesson of timetable[day] | week; let i = index" [ngClass]="{'hide': lesson == undefined}" (click)="onEditOrAdd(undefined, {lesson, day, time: i})" [lesson]="lesson" [courses]="courses" />
</div>
</section>
</ion-content>

View File

@@ -2,19 +2,6 @@
margin-bottom: 16px;
}
.icon {
margin-inline: auto;
aspect-ratio: 1;
width: max-content;
padding: 10px;
border-radius: 50%;
line-height: 20px;
background-color: var(--background);
color: var(--foreground);
}
.courses {
ion-item {
--background: transparent;
@@ -48,15 +35,6 @@
flex-basis: 0;
padding-block: 16px;
}
ion-card {
margin: 10px 0 0;
width: 100%;
ion-card-header, ion-card-content {
padding: 7px;
}
}
}
.hide {

View File

@@ -5,13 +5,14 @@ import {IonicModule, IonModal} from '@ionic/angular';
import {IServService} from "../../api/iserv.service";
import {Course, Lesson, Timetable} from "../../entities/course";
import {WeekPipe} from "../../pipes/week.pipe";
import {LessonComponent} from "../../components/lesson/lesson.component";
@Component({
selector: 'app-schedule',
templateUrl: './schedule.page.html',
styleUrls: ['./schedule.page.scss'],
standalone: true,
imports: [IonicModule, CommonModule, FormsModule, WeekPipe]
imports: [IonicModule, CommonModule, FormsModule, WeekPipe, LessonComponent]
})
export class SchedulePage implements OnInit {
@@ -20,48 +21,14 @@ export class SchedulePage implements OnInit {
public currentCourse: Course;
public timetable: Timetable = {mon: [], tue: [], wed: [], thu: [], fri: []};
public currentLesson: {lesson: Lesson, day: string, time: number};
public rerender: boolean = false;
public colors: {name: string; val: string}[] = [
{name: "Blau", val: "primary"},
{name: "Hellblau", val: "secondary"},
{name: "Lila", val: "tertiary"},
{name: "Grün", val: "success"},
{name: "Gelb", val: "warning"},
{name: "Rot", val: "danger"}
];
@ViewChild('courseModal') courseModal: IonModal;
@ViewChild('tableModal') tableModal: IonModal;
constructor(private iserv: IServService) { }
constructor(public iserv: IServService) { }
async ngOnInit() {
if (localStorage.getItem("courses") == undefined) {
const data = await this.iserv.getCoursesAndClass();
if (data.class.startsWith("Q")) {
for (let course of data.courses) {
const short = course.substring(1, 3);
const name = this.iserv.courseNames[short];
if (name == undefined) continue;
this.courses.push({
id: course,
short: short.toUpperCase(),
name: name,
color: this.colors[Math.floor(Math.random() * this.colors.length)].val
});
}
this.courses.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
localStorage.setItem("courses", JSON.stringify(this.courses));
}
}else {
this.courses = JSON.parse(localStorage.getItem("courses"));
}
this.courses = (await this.iserv.getCoursesAndClass()).courses;
if (localStorage.getItem("timetable") == undefined) {
for (let day of ['mon', 'tue', 'wed', 'thu', 'fri']) {
@@ -120,10 +87,4 @@ export class SchedulePage implements OnInit {
location.reload();
}
public findCourse(id: string): Course {
for (let course of this.courses)
if (course.id == id) return course;
return undefined;
}
}

View File

@@ -42,19 +42,7 @@
<ion-checkbox justify="space-between" [(ngModel)]="filterByClasses" (ionChange)="showOnlyCourses(classes.checked)" #classes>Nur eigene Kurse anzeigen</ion-checkbox>
</ion-item>
<ion-card
*ngFor="let subs of data?.substitutions"
class="subs {{subs.type.replace(' ', '').replace('.', '')}}"
[ngClass]="{'hide': (subs.classes.indexOf(currentClass) == -1 && currentClass != 'all') || !hasClass(subs.lesson)}"
>
<ion-card-content>
<ion-label class="times">{{subs.times.join(" - ")}}</ion-label>
<div>
<ion-label class="type">{{subs.type}}</ion-label>
<ion-label class="desc" [innerHtml]="getDetails(subs)"></ion-label>
</div>
</ion-card-content>
</ion-card>
<substitution *ngFor="let subs of data?.substitutions" [subs]="subs" [ngClass]="{'hide': (subs.classes.indexOf(currentClass) == -1 && currentClass != 'all') || !hasClass(subs.lesson)}" />
</section>
</ion-content>

View File

@@ -1,48 +1,3 @@
.subs {
ion-card-content {
display: flex;
gap: 15px;
color: #FFF;
.times {
font-size: 25px;
line-height: 25px;
align-self: center;
}
div {
margin-left: auto;
display: flex;
flex-direction: column;
align-items: flex-end;
.type {
font-size: 18px;
}
}
}
&.Raumtausch {
--background: var(--ion-color-success-shade);
}
&.bittebeachten, &.stregulärem {
--background: var(--ion-color-tertiary-shade);
}
&.Vertretung {
--background: var(--ion-color-primary-shade);
}
&.Entfall, &.Stillarbeit {
--background: var(--ion-color-danger-shade);
}
&.Verlegung {
--background: var(--ion-color-warning-shade);
}
&.hide {
display: none;
}
.hide {
display: none;
}

View File

@@ -1,18 +1,18 @@
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {Component, OnInit} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {AlertController, IonicModule} from '@ionic/angular';
import {UnitsService} from "../../api/units.service";
import {Substitution, UnitsData} from "../../entities/substitution";
import {UnitsData} from "../../entities/substitution";
import {IServService} from "../../api/iserv.service";
import {Course} from "../../entities/course";
import {SubstitutionComponent} from "../../components/substitution/substitution.component";
@Component({
selector: 'app-substitution',
templateUrl: './substitution.page.html',
styleUrls: ['./substitution.page.scss'],
standalone: true,
imports: [IonicModule, CommonModule, FormsModule]
imports: [IonicModule, CommonModule, FormsModule, SubstitutionComponent]
})
export class SubstitutionPage implements OnInit {
@@ -42,29 +42,23 @@ export class SubstitutionPage implements OnInit {
this.data = await this.units.getSubstitutionPlan("today");
const data = await this.iserv.getCoursesAndClass();
if (localStorage.getItem("class") == null) {
if (!data.class.startsWith("Q")) {
this.changeClass(data.class);
}else {
this.changeClass(data.class);
if (data.class.startsWith("Q")) {
for (let course of data.courses) {
this.courses.push(course.id);
}
if (localStorage.getItem("filterByClasses") == null) {
this.showOnlyCourses(true);
this.filterByClasses = true;
}
}
if (data.class.startsWith("Q")) {
if (localStorage.getItem("courses") != undefined) {
const courses = JSON.parse(localStorage.getItem("courses")) as Course[];
for (let course of courses) {
this.courses.push(course.id);
if (data.courses.length == 0) {
const alert = await this.alerts.create({
header: "Achtung",
message: "Füge deine Kurse im Stundenplan hinzu um sie hier zu filtern!",
buttons: ["Ok"]
});
await alert.present();
}
}else {
const alert = await this.alerts.create({
header: "Achtung",
message: "Füge deine Kurse im Stundenplan hinzu um sie hier zu filtern!",
buttons: ["Ok"]
});
await alert.present();
}
}
}
@@ -81,40 +75,6 @@ export class SubstitutionPage implements OnInit {
this.showOnlyCourses(false);
}
public getDetails(subs: Substitution): string {
if (subs.type == "bitte beachten") {
const desc = subs.description != "&nbsp;" ? ' - ' + subs.description : "";
let info = `${subs.lesson} (${subs.teacher}) in ${subs.room}`;
if (subs.lesson != subs.newLesson) {
info = `${subs.newLesson} (${subs.representative}) statt ${subs.lesson} (${subs.teacher}) in ${subs.room}`;
}
return info + desc;
}
switch (subs.type) {
case "Vertretung":
case "st. regulärem Unt.":
return `${subs.lesson} (${subs.representative} statt ${subs.teacher}) in ${subs.room}`;
case "Raumtausch":
return `${subs.lesson} (${subs.teacher}) in ${subs.room}`;
case "Entfall":
return `${subs.lesson} (${subs.teacher})`;
case "Stillarbeit":
return `${subs.lesson} (${subs.teacher}) in ${subs.room}`;
case "Verlegung":
return `${subs.newLesson} (${subs.representative}) statt ${subs.lesson} (${subs.teacher}) in ${subs.room}`;
default:
return subs.lesson + ' (' + subs.teacher + ') ' + subs.room;
}
}
public showOnlyCourses(toggle: boolean) {
localStorage.setItem("filterByClasses", toggle.toString());
}

View File

@@ -1,38 +0,0 @@
<ion-header [translucent]="true">
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Aufgaben</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Aufgaben</ion-title>
</ion-toolbar>
</ion-header>
<ion-label>Coming soon!</ion-label>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-grid>
<ion-row>
<ion-col>
<ion-tab-button>
<ion-icon ios="list-outline" md="list-sharp" />
Aktuelle Aufgaben
</ion-tab-button>
</ion-col>
<ion-col>
<ion-tab-button>
<ion-icon ios="folder-outline" md="folder-sharp" />
Vergangene Aufgaben
</ion-tab-button>
</ion-col>
</ion-row>
</ion-grid>
</ion-toolbar>
</ion-footer>

View File

@@ -1,20 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
@Component({
selector: 'app-tasks',
templateUrl: './tasks.page.html',
styleUrls: ['./tasks.page.scss'],
standalone: true,
imports: [IonicModule, CommonModule, FormsModule]
})
export class TasksPage implements OnInit {
constructor() { }
ngOnInit() {
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

View File

@@ -1,3 +1,4 @@
export const environment = {
production: true
production: true,
backend: "https://iserv.leon-hoppe.de"
};

View File

@@ -3,7 +3,8 @@
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
production: false,
backend: "http://localhost:5273"
};
/*

View File

@@ -36,3 +36,15 @@ ion-menu-button {
.active {
color: var(--ion-color-primary);
}
.lesson-icon {
margin-inline: auto;
aspect-ratio: 1;
width: 45px;
padding: 10px;
border-radius: 50%;
line-height: 25px;
background-color: var(--background);
color: var(--foreground);
}

View File

@@ -12,7 +12,7 @@
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<link rel="icon" type="image/png" href="assets/icon/favicon.png" />
<link rel="icon" type="image/png" href="assets/icon/favicon.ico" />
<!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" />