Add feature to assign user to course, add date editing support
It seems like the button click event doesn't work in an ngFor. That took a while to debug
This commit is contained in:
parent
0ea057eee1
commit
ef5e2f6cfb
16 changed files with 109 additions and 20 deletions
|
@ -40,4 +40,13 @@ export class CourseResolver {
|
||||||
await this.courseRepo.create(input);
|
await this.courseRepo.create(input);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mutation(returns => Boolean)
|
||||||
|
async courseAssignUser(@arg('course', returns => ID) course: number, @arg('user', returns => ID) user: number, @arg('role') role: string): Promise<boolean> {
|
||||||
|
if (role !== 'teacher' && role !== 'student') {
|
||||||
|
throw new Error('Érvénytelen szerepkör');
|
||||||
|
}
|
||||||
|
await this.courseRepo.users(course).link(user, {throughData: {role: role}});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import {Component, OnInit} from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import {AbstractControl, FormControl, ValidationErrors, Validators} from '@angular/forms';
|
import { AbstractControl, FormControl, ValidationErrors, Validators } from '@angular/forms';
|
||||||
import {LoginService} from '../login.service';
|
import { LoginService } from '../login.service';
|
||||||
import {Router} from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import {FormErrorStateMatcher} from '../../utility/form-error-state-matcher';
|
import { FormErrorStateMatcher } from '../../utility/form-error-state-matcher';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-register',
|
selector: 'app-register',
|
||||||
|
@ -74,8 +74,7 @@ export class RegisterComponent implements OnInit {
|
||||||
try {
|
try {
|
||||||
await this.loginService.createUser(this.emailFormControl.value, this.passFormControl.value, this.nameFormControl.value);
|
await this.loginService.createUser(this.emailFormControl.value, this.passFormControl.value, this.nameFormControl.value);
|
||||||
await this.router.navigate(['/']);
|
await this.router.navigate(['/']);
|
||||||
} catch (e) {
|
} catch (e) { // A GraphQL már kiirja
|
||||||
alert(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,7 @@ mutation EditCourse($input: CourseUpdateInput!) {
|
||||||
mutation CreateCourse($input: CourseCreateInput!) {
|
mutation CreateCourse($input: CourseCreateInput!) {
|
||||||
courseCreate(course: $input)
|
courseCreate(course: $input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutation CourseAssignUser($user: ID!, $course: ID!, $role: String!) {
|
||||||
|
courseAssignUser(user: $user, course: $course, role: $role)
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
</span>
|
</span>
|
||||||
<span *ngSwitchCase="'date'">
|
<span *ngSwitchCase="'date'">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-datepicker [formControlName]="field.name" [ngModel]="item[field.name]"></mat-datepicker>
|
<input matInput [formControlName]="field.name" [matDatepicker]="datePicker" [value]="item[field.name]"/>
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #datePicker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</span>
|
</span>
|
||||||
<mat-form-field *ngSwitchDefault>
|
<mat-form-field *ngSwitchDefault>
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class EditComponent<T extends HasID, QT extends QueryResult<T>, UT extend
|
||||||
implements OnInit {
|
implements OnInit {
|
||||||
|
|
||||||
item?: T;
|
item?: T;
|
||||||
@Input() creating = false;
|
creating = false;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
@Input() gql: Query<QT, HasID>;
|
@Input() gql: Query<QT, HasID>;
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||||
|
import { MatNativeDateModule } from '@angular/material/core';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -35,7 +36,8 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatDatepickerModule
|
MatDatepickerModule,
|
||||||
|
MatNativeDateModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedComponentsModule {
|
export class SharedComponentsModule {
|
||||||
|
|
|
@ -24,9 +24,12 @@
|
||||||
<button *ngIf="allowEditing" mat-icon-button color="primary" (click)="editItem.emit(item)">
|
<button *ngIf="allowEditing" mat-icon-button color="primary" (click)="editItem.emit(item)">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button *ngFor="let action of customActions" mat-icon-button color="primary" (click)="action.action(item)">
|
<ng-container *ngFor="let action of customActions">
|
||||||
<mat-icon [matTooltip]="action.label">{{ action.icon }}</mat-icon>
|
<button *ngIf="action.icon" mat-icon-button color="primary" (click)="action.action(item)">
|
||||||
</button>
|
<mat-icon [matTooltip]="action.label">{{ action.icon }}</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="!action.icon" mat-button (mouseup)="action.action(item)">{{ action.label }}</button>
|
||||||
|
</ng-container>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<tr mat-header-row *matHeaderRowDef="getPropNames()"></tr>
|
<tr mat-header-row *matHeaderRowDef="getPropNames()"></tr>
|
||||||
|
|
|
@ -24,6 +24,9 @@ export class TableComponent<T> implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
if (typeof this.allowEditing === 'string') {
|
||||||
|
throw new Error('use [allowEditing]');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPropNames(): string[] {
|
getPropNames(): string[] {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{title: 'Félév', name: 'semester'},
|
{title: 'Félév', name: 'semester'},
|
||||||
{title: 'Név', name: 'alias'}
|
{title: 'Név', name: 'alias'}
|
||||||
]"></app-edit>
|
]"></app-edit>
|
||||||
|
<button mat-raised-button style="margin-top: 20px" (click)="assignUsers()">Felhasználók hozzárendelése</button>
|
||||||
<mat-card style="margin-top: 50px">
|
<mat-card style="margin-top: 50px">
|
||||||
<mat-card-header>
|
<mat-card-header>
|
||||||
<h3>Teljesitési módok</h3>
|
<h3>Teljesitési módok</h3>
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<app-list [gql]="modeListGQL" [queryVariables]="{course: courseId}" [columns]="[
|
<app-list [gql]="modeListGQL" [queryVariables]="{course: courseId}" [columns]="[
|
||||||
{prop: 'name', title: 'Név'}
|
{prop: 'name', title: 'Név'}
|
||||||
]" allowEditing="true" allowNew="true" [editFunction]="editFulMode.bind(this)"
|
]" allowNew="true" [editFunction]="editFulMode.bind(this)"
|
||||||
[createFunction]="createFulMode.bind(this)"></app-list>
|
[createFunction]="createFulMode.bind(this)"></app-list>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
@ -40,7 +41,7 @@
|
||||||
{prop: 'minPoints', title: 'Minimum elérendő pontszám'},
|
{prop: 'minPoints', title: 'Minimum elérendő pontszám'},
|
||||||
{prop: 'maxPoints', title: 'Maximálisan elérhető pontszám'},
|
{prop: 'maxPoints', title: 'Maximálisan elérhető pontszám'},
|
||||||
{prop: 'deadline', title: 'Határidő', type: 'date'}
|
{prop: 'deadline', title: 'Határidő', type: 'date'}
|
||||||
]" allowEditing="true" allowNew="true" [editFunction]="editRequirement.bind(this)"
|
]" allowNew="true" [editFunction]="editRequirement.bind(this)"
|
||||||
[createFunction]="createRequirement.bind(this)"></app-list>
|
[createFunction]="createRequirement.bind(this)"></app-list>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
{{ editedRequirement?.name || 'Új követelmény' }}
|
{{ editedRequirement?.name || 'Új követelmény' }}
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<app-edit [itemType]="editedRequirement" creating="true" [createMutation]="requirementCreateGQL"
|
<app-edit [itemType]="editedRequirement" [createMutation]="requirementCreateGQL"
|
||||||
[updateMutation]="requirementEditGQL" [customItem]="editedRequirement" [fields]="[
|
[updateMutation]="requirementEditGQL" [customItem]="editedRequirement" [fields]="[
|
||||||
{name: 'name', title: 'Név'},
|
{name: 'name', title: 'Név'},
|
||||||
{name: 'description', title: 'Leirás'},
|
{name: 'description', title: 'Leirás'},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { CustomTitleComponent } from '../../../../app.component';
|
import { CustomTitleComponent } from '../../../../app.component';
|
||||||
import {
|
import {
|
||||||
Course,
|
Course,
|
||||||
|
@ -40,7 +40,8 @@ export class CourseEditComponent implements OnInit, CustomTitleComponent {
|
||||||
public itemGQL: CourseGQL, public editGQL: EditCourseGQL, public createGQL: CreateCourseGQL,
|
public itemGQL: CourseGQL, public editGQL: EditCourseGQL, public createGQL: CreateCourseGQL,
|
||||||
public modeListGQL: FulfillmentModeListGQL, public modeItemGQL: FulfillmentModeGQL, public modeEditGQL: EditFulfillmentModeGQL,
|
public modeListGQL: FulfillmentModeListGQL, public modeItemGQL: FulfillmentModeGQL, public modeEditGQL: EditFulfillmentModeGQL,
|
||||||
public modeCreateGQL: CreateFulfillmentModeGQL, public requirementListGQL: RequirementListGQL, public requirementGQL: RequirementGQL,
|
public modeCreateGQL: CreateFulfillmentModeGQL, public requirementListGQL: RequirementListGQL, public requirementGQL: RequirementGQL,
|
||||||
public requirementEditGQL: EditRequirementGQL, public requirementCreateGQL: CreateRequirementGQL) {
|
public requirementEditGQL: EditRequirementGQL, public requirementCreateGQL: CreateRequirementGQL,
|
||||||
|
private router: Router) {
|
||||||
this.subjectId = route.snapshot.params.subjectId;
|
this.subjectId = route.snapshot.params.subjectId;
|
||||||
this.courseId = route.snapshot.params.id;
|
this.courseId = route.snapshot.params.id;
|
||||||
}
|
}
|
||||||
|
@ -101,4 +102,8 @@ export class CourseEditComponent implements OnInit, CustomTitleComponent {
|
||||||
this.editingRequirement = false;
|
this.editingRequirement = false;
|
||||||
this.editedRequirement = null;
|
this.editedRequirement = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async assignUsers(): Promise<void> {
|
||||||
|
await this.router.navigate(['users', 'assign'], {queryParams: {course: this.courseId}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', component: SubjectListComponent, data: {title: ''} as RouteData},
|
{path: '', component: SubjectListComponent, data: {title: ''} as RouteData},
|
||||||
|
@ -32,7 +33,8 @@ const routes: Routes = [
|
||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule,
|
||||||
|
MatButtonModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SubjectsModule {
|
export class SubjectsModule {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<app-list [itemType]="itemType" [allowEditing]="false" [gql]="listGQL" [customActions]="[
|
||||||
|
{action: assignAsTeacher.bind(this), label: 'Oktatóként', icon: ''},
|
||||||
|
{action: assignAsStudent.bind(this), label: 'Hallgatóként', icon: ''}
|
||||||
|
]" [columns]="[
|
||||||
|
{title: 'Név', prop: 'name'}
|
||||||
|
]"></app-list>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AssignToCourseComponent } from './assign-to-course.component';
|
||||||
|
|
||||||
|
describe('AssignToCourseComponent', () => {
|
||||||
|
let component: AssignToCourseComponent;
|
||||||
|
let fixture: ComponentFixture<AssignToCourseComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [AssignToCourseComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AssignToCourseComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { CourseAssignUserGQL, User, UserListGQL } from '../../services/graphql';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-assign-to-course',
|
||||||
|
templateUrl: './assign-to-course.component.html',
|
||||||
|
styleUrls: ['./assign-to-course.component.css']
|
||||||
|
})
|
||||||
|
export class AssignToCourseComponent implements OnInit {
|
||||||
|
itemType: User;
|
||||||
|
|
||||||
|
constructor(public listGQL: UserListGQL, public assignGQL: CourseAssignUserGQL, private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignAsTeacher(item: User): Promise<void> { // TODO: Remove assigned users from list
|
||||||
|
await this.assignGQL.mutate({course: this.route.snapshot.queryParams.course, user: item.id + '', role: 'teacher'}).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignAsStudent(item: User): Promise<void> {
|
||||||
|
await this.assignGQL.mutate({course: this.route.snapshot.queryParams.course, user: item.id + '', role: 'student'}).toPromise();
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,14 +5,16 @@ import { RouterModule, Routes } from '@angular/router';
|
||||||
import { RouteData } from '../app-routing.module';
|
import { RouteData } from '../app-routing.module';
|
||||||
import { SharedComponentsModule } from '../shared-components/shared-components.module';
|
import { SharedComponentsModule } from '../shared-components/shared-components.module';
|
||||||
import { UserEditComponent } from './user-edit/user-edit.component';
|
import { UserEditComponent } from './user-edit/user-edit.component';
|
||||||
|
import { AssignToCourseComponent } from './assign-to-course/assign-to-course.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', component: UserListComponent, data: {title: ''} as RouteData},
|
{path: '', component: UserListComponent, data: {title: ''} as RouteData},
|
||||||
|
{path: 'assign', component: AssignToCourseComponent, data: {title: 'Hozzárendelés kurzushoz'}},
|
||||||
{path: ':id', component: UserEditComponent, data: {title: 'Szerkesztés'}}
|
{path: ':id', component: UserEditComponent, data: {title: 'Szerkesztés'}}
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [UserListComponent, UserEditComponent],
|
declarations: [UserListComponent, UserEditComponent, AssignToCourseComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
RouterModule.forChild(routes),
|
RouterModule.forChild(routes),
|
||||||
|
|
Loading…
Reference in a new issue