PUNKT-11 Front-end aplikacji StudyCave
This commit is contained in:
parent
6a5655cca9
commit
5fefcef27f
68
.angular-cli.json
Normal file
68
.angular-cli.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "study-cave"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"./favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
|
||||
"../node_modules/primeicons/primeicons.css",
|
||||
"../node_modules/primeng/resources/primeng.min.css",
|
||||
"../node_modules/primeng/resources/themes/luna-amber/theme.css",
|
||||
"../node_modules/primeng/resources/components/dialog/dialog.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [
|
||||
"../node_modules/jquery/dist/jquery.min.js",
|
||||
"../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
|
||||
],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
43
.gitignore
vendored
Normal file
43
.gitignore
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
package-lock.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
7
.htaccess
Normal file
7
.htaccess
Normal file
@ -0,0 +1,7 @@
|
||||
Options +FollowSymLinks
|
||||
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} !index
|
||||
RewriteRule (.*) index.html [L]
|
18
.vscode/launch.json
vendored
Normal file
18
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceFolder}\\serve",
|
||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/out-tsc/**/*.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
14
e2e/app.e2e-spec.ts
Normal file
14
e2e/app.e2e-spec.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('study-cave App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
11
e2e/app.po.ts
Normal file
11
e2e/app.po.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
14
e2e/tsconfig.e2e.json
Normal file
14
e2e/tsconfig.e2e.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
33
karma.conf.js
Normal file
33
karma.conf.js
Normal file
@ -0,0 +1,33 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
68
package.json
Normal file
68
package.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "study-cave",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^5.0.0",
|
||||
"@angular/cdk": "^5.2.5",
|
||||
"@angular/common": "^5.0.0",
|
||||
"@angular/compiler": "^5.0.0",
|
||||
"@angular/core": "^5.0.0",
|
||||
"@angular/forms": "^5.0.0",
|
||||
"@angular/http": "^5.0.0",
|
||||
"@angular/material": "^5.2.5",
|
||||
"@angular/platform-browser": "^5.0.0",
|
||||
"@angular/platform-browser-dynamic": "^5.0.0",
|
||||
"@angular/router": "^5.0.0",
|
||||
"@auth0/angular-jwt": "^2.0.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.10",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.6.1",
|
||||
"ag-grid-angular": "^19.1.2",
|
||||
"ag-grid-community": "^19.1.4",
|
||||
"ajv": "^6.0.0",
|
||||
"angular-font-awesome": "^3.1.2",
|
||||
"angular2-jwt": "^0.2.3",
|
||||
"bootstrap": "^4.1.2",
|
||||
"core-js": "^2.4.1",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jquery": "^3.3.1",
|
||||
"jquery-ui": "^1.12.1",
|
||||
"picasso.js": "^0.18.2",
|
||||
"popper.js": "^1.12.9",
|
||||
"primeicons": "^1.0.0",
|
||||
"primeng": "^6.1.7",
|
||||
"rxjs": "^5.5.2",
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/core": "^7.1.2",
|
||||
"@angular/cli": "^1.7.4",
|
||||
"@angular/compiler-cli": "^5.0.0",
|
||||
"@angular/language-service": "^5.0.0",
|
||||
"@types/jasmine": "~2.5.53",
|
||||
"@types/jasminewd2": "~2.0.2",
|
||||
"@types/node": "~6.0.60",
|
||||
"codelyzer": "^4.0.1",
|
||||
"jasmine-core": "~2.5.2",
|
||||
"jasmine-spec-reporter": "~4.1.0",
|
||||
"karma": "~1.7.0",
|
||||
"karma-chrome-launcher": "~2.1.1",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.2.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.1.2",
|
||||
"ts-node": "~3.2.0",
|
||||
"tslint": "~5.7.0",
|
||||
"typescript": "~2.4.2"
|
||||
}
|
||||
}
|
28
protractor.conf.js
Normal file
28
protractor.conf.js
Normal file
@ -0,0 +1,28 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
108
src/app/app-routing.module.ts
Normal file
108
src/app/app-routing.module.ts
Normal file
@ -0,0 +1,108 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { FlashcardsModule } from './flashcards/flashcards.module';
|
||||
import { TestsModule } from './tests/tests.module';
|
||||
import { UserModule } from './user/user.module';
|
||||
import { GroupsModule } from './groups/groups.module';
|
||||
|
||||
import { AuthGuard } from './auth-guard.service';
|
||||
|
||||
import { FlashcardsComponent } from './flashcards/flashcards/flashcards.component';
|
||||
import { FlashcardsSetsListComponent } from './flashcards/flashcards-sets-list/flashcards-sets-list.component';
|
||||
import { FlashcardsAddComponent } from './flashcards/flashcards-add/flashcards-add.component';
|
||||
import { FlashcardsAddCsvComponent } from './flashcards/flashcards-add-csv/flashcards-add-csv.component';
|
||||
import { FlashcardsAddTableComponent } from './flashcards/flashcards-add-table/flashcards-add-table.component';
|
||||
import { FlashcardsSetDetailComponent } from './flashcards/flashcards-set-detail/flashcards-set-detail.component';
|
||||
import { FlashcardsPairsTestComponent } from './flashcards/flashcards-pairs-test/flashcards-pairs-test.component';
|
||||
import { FlashcardsMemoryTestComponent } from './flashcards/flashcards-memory-test/flashcards-memory-test.component';
|
||||
import { FlashcardsEditTableComponent } from './flashcards/flashcards-edit-table/flashcards-edit-table.component';
|
||||
import { FlashcardsFillingInTestComponent } from './flashcards/flashcards-filling-in-test/flashcards-filling-in-test.component';
|
||||
import { FlashcardsTyperaceTestComponent } from './flashcards/flashcards-typerace-test/flashcards-typerace-test.component';
|
||||
import { HomePageComponent } from './home-page/home-page.component';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { TestMakerComponent } from './tests/test-maker/test-maker.component';
|
||||
import { TestEditComponent } from './tests/test-edit/test-edit.component';
|
||||
import { RegisterComponent } from './user/register/register.component';
|
||||
import { UserComponent } from './user/user/user.component';
|
||||
import { EditUserComponent } from './user/edit-user/edit-user.component';
|
||||
import { MaterialsMenuComponent } from './materials/materials-menu/materials-menu.component';
|
||||
import { MaterialsListComponent } from './materials/materials-list/materials-list.component';
|
||||
import { MaterialsAddComponent } from './materials/materials-add/materials-add.component';
|
||||
import { TestsListComponent } from './tests/tests-list/tests-list.component';
|
||||
import { WorkInProgressComponent } from './work-in-progress/work-in-progress.component';
|
||||
import { TestDetailsComponent } from './tests/test-details/test-details.component';
|
||||
import { MaterialsDetailsComponent } from './materials/materials-details/materials-details.component';
|
||||
import { MyGroupsComponent } from './groups/my-groups/my-groups.component';
|
||||
import { GroupCreatorComponent } from './groups/group-creator/group-creator.component';
|
||||
import { JoinToGroupComponent } from './groups/join-to-group/join-to-group.component';
|
||||
import { GroupDetailsComponent } from './groups/group-details/group-details.component';
|
||||
import { ManageGroupComponent } from './groups/manage-group/manage-group.component';
|
||||
import { SharingResourcesInGroupsComponent } from './groups/sharing-resources-in-groups/sharing-resources-in-groups.component';
|
||||
import { CommentsComponent } from './shared/comments/comments.component';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
import { WaitingResourcesComponent } from './groups/waiting-resources/waiting-resources.component';
|
||||
import { BagdesComponent } from './user/bagdes/bagdes.component';
|
||||
import { RankingComponent } from './groups/ranking/ranking.component';
|
||||
import { HistoryOfActivityInGroupComponent } from './groups/history-of-activity-in-group/history-of-activity-in-group.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: '', component: HomePageComponent },
|
||||
{ path: 'home', component: HomePageComponent },
|
||||
{ path: 'flashcards', component: FlashcardsComponent },
|
||||
{ path: 'flashcards/sets', component: FlashcardsSetsListComponent },
|
||||
{ path: 'flashcards/add', component: FlashcardsAddComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'flashcards/add/table', component: FlashcardsAddTableComponent , canActivate: [AuthGuard]},
|
||||
{ path: 'flashcards/add/csv', component: FlashcardsAddCsvComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'flashcards/sets/:id', component: FlashcardsSetDetailComponent },
|
||||
{ path: 'flashcards/test-gen/flashcards-pairs/:id', component: FlashcardsPairsTestComponent },
|
||||
{ path: 'flashcards/test-gen/flashcards-memory/:id', component: FlashcardsMemoryTestComponent },
|
||||
{ path: 'flashcards/test-gen/flashcards-typerace/:id', component: FlashcardsTyperaceTestComponent },
|
||||
{ path: 'flashcards/test-gen/flashcards-filling-in/:id', component: FlashcardsFillingInTestComponent },
|
||||
{ path: 'flashcards/sets/edit/:id', component: FlashcardsEditTableComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'tests', component: TestsListComponent},
|
||||
{ path: 'tests/:id', component: TestDetailsComponent},
|
||||
{ path: 'tests/edit/:id', component: TestEditComponent, canActivate: [AuthGuard]},
|
||||
{ path: 'test-maker', component: TestMakerComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'sign-up', component: RegisterComponent },
|
||||
{ path: 'profile/:id', component: UserComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'edit-profile', component: EditUserComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'materials', component: MaterialsMenuComponent },
|
||||
{ path: 'materials/list', component: MaterialsListComponent },
|
||||
{ path: 'materials/add-materials', component: MaterialsAddComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'work-in-progress', component: WorkInProgressComponent },
|
||||
{ path: 'materials/:id', component: MaterialsDetailsComponent},
|
||||
{ path: 'my-groups', component: MyGroupsComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'create-group', component: GroupCreatorComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'join-to-group', component: JoinToGroupComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'groups/:id', component: GroupDetailsComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'groups/manage/:id', component: ManageGroupComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'groups/add-resources/:id', component: SharingResourcesInGroupsComponent , canActivate: [AuthGuard] },
|
||||
{ path: 'groups/waiting-resources/:id', component: WaitingResourcesComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'badges', component: BagdesComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'groups/ranking/:id', component: RankingComponent , canActivate: [AuthGuard] },
|
||||
{ path: 'groups/waiting-resources/:id', component: WaitingResourcesComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'groups/waiting-resources/:id', component: WaitingResourcesComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'groups/history/:id', component: HistoryOfActivityInGroupComponent, canActivate: [AuthGuard] }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload', useHash: false}),
|
||||
FlashcardsModule,
|
||||
TestsModule,
|
||||
UserModule,
|
||||
GroupsModule,
|
||||
SharedModule
|
||||
],
|
||||
exports: [
|
||||
RouterModule,
|
||||
FlashcardsModule,
|
||||
TestsModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
]
|
||||
})
|
||||
export class AppRoutingModule { }
|
30
src/app/app.component.css
Normal file
30
src/app/app.component.css
Normal file
@ -0,0 +1,30 @@
|
||||
.content{
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
margin-top: 100px;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
height: calc(100vh - 154px);
|
||||
min-height: calc(100vh - 154px);
|
||||
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.content{
|
||||
margin-top: 170px;
|
||||
height: calc(100vh - 200px);
|
||||
min-height: calc(100vh - 200px);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 352px) {
|
||||
.content{
|
||||
margin-top: 170px;
|
||||
height: calc(100vh - 250px);
|
||||
min-height: calc(100vh - 250px);
|
||||
}
|
||||
}
|
8
src/app/app.component.html
Normal file
8
src/app/app.component.html
Normal file
@ -0,0 +1,8 @@
|
||||
<div class="wrapper">
|
||||
<app-main-navigation></app-main-navigation>
|
||||
<div class="content">
|
||||
<router-outlet></router-outlet>
|
||||
<br /><br /><br /><br />
|
||||
</div>
|
||||
<app-footer></app-footer>
|
||||
</div>
|
31
src/app/app.component.spec.ts
Normal file
31
src/app/app.component.spec.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { RoutingStateService } from './routing-state.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
let component: AppComponent;
|
||||
let fixture: ComponentFixture<AppComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
providers: [RoutingStateService],
|
||||
imports: [RouterTestingModule],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AppComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create the app', async(() => {
|
||||
expect(component).toBeTruthy();
|
||||
}));
|
||||
});
|
17
src/app/app.component.ts
Normal file
17
src/app/app.component.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { RoutingStateService } from './routing-state.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
title = 'app';
|
||||
|
||||
constructor(routingState: RoutingStateService) {
|
||||
routingState.loadRouting();
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
60
src/app/app.module.ts
Normal file
60
src/app/app.module.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { MaterialsModule } from './materials/materials.module';
|
||||
import { FlashcardsModule } from './flashcards/flashcards.module';
|
||||
import { TestsModule } from './tests/tests.module';
|
||||
import { GroupsModule } from './groups/groups.module';
|
||||
import { UserModule } from './user/user.module';
|
||||
|
||||
import { httpInterceptorProviders } from './http-interceptors/index';
|
||||
import { LocationStrategy, HashLocationStrategy, PathLocationStrategy } from '@angular/common';
|
||||
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { AppComponent } from './app.component';
|
||||
import { MainNavigationComponent } from './main-navigation/main-navigation.component';
|
||||
import { FooterComponent } from './footer/footer.component';
|
||||
import { HomePageComponent } from './home-page/home-page.component';
|
||||
import { WorkInProgressComponent } from './work-in-progress/work-in-progress.component';
|
||||
|
||||
import { AuthGuard } from './auth-guard.service';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
import { RoutingStateService } from './routing-state.service';
|
||||
|
||||
import { AutofocusDirective } from './autofocus.directive';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LoginComponent,
|
||||
AppComponent,
|
||||
MainNavigationComponent,
|
||||
FooterComponent,
|
||||
HomePageComponent,
|
||||
WorkInProgressComponent,
|
||||
AutofocusDirective
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule,
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
FlashcardsModule,
|
||||
MaterialsModule,
|
||||
TestsModule,
|
||||
GroupsModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
providers: [AuthGuard, httpInterceptorProviders, AuthenticationService, RoutingStateService, {
|
||||
provide: LocationStrategy, useClass: PathLocationStrategy
|
||||
}],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
16
src/app/auth-guard.service.spec.ts
Normal file
16
src/app/auth-guard.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AuthGuard } from './auth-guard.service';
|
||||
|
||||
describe('AuthGuardService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [AuthGuard],
|
||||
imports: [RouterTestingModule]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([AuthGuard], (service: AuthGuard) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
19
src/app/auth-guard.service.ts
Normal file
19
src/app/auth-guard.service.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private router: Router) {
|
||||
}
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
// logged in so return true
|
||||
return true;
|
||||
}
|
||||
// tslint:disable-next-line:one-line
|
||||
else {
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
19
src/app/authentication.service.spec.ts
Normal file
19
src/app/authentication.service.spec.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('AuthenticationService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [AuthenticationService],
|
||||
imports: [HttpClientModule, MatSnackBarModule],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([AuthenticationService], (service: AuthenticationService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
71
src/app/authentication.service.ts
Normal file
71
src/app/authentication.service.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Injectable, Output, EventEmitter } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpRequest, HttpEvent } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/observable/throw';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationService {
|
||||
@Output() getLoggedInName: EventEmitter<any> = new EventEmitter();
|
||||
private headers = new HttpHeaders({ 'Content-Type': 'application/json' });
|
||||
private storageSub = new Subject<boolean>();
|
||||
public token: string;
|
||||
constructor(private http: HttpClient, public snackBar: MatSnackBar) {
|
||||
}
|
||||
|
||||
watchStorage(): Observable<any> {
|
||||
return this.storageSub.asObservable();
|
||||
}
|
||||
|
||||
watchStorageChanges(): void {
|
||||
this.storageSub.next(true);
|
||||
}
|
||||
|
||||
|
||||
login(username: string, password: string): Observable<boolean> {
|
||||
return this.http.post('login', { password: password, username: username }, { headers: this.headers, observe: 'response' })
|
||||
.map((response) => {
|
||||
// czy login ok jeśli w response jest token
|
||||
// const token = response.json() && response.json().token;
|
||||
const token = response.headers.get('authorization');
|
||||
if (token) {
|
||||
// store username and jwt token w local storage aby nie wylogowało przy zmianie stron
|
||||
localStorage.setItem('currentUser', JSON.stringify({ username: username, authorization: token }));
|
||||
this.getLoggedInName.emit('logged');
|
||||
this.storageSub.next(true);
|
||||
this.snackBar.open('Zalogowano pomyślnie!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-success'] });
|
||||
// return true jeśli ok
|
||||
return true;
|
||||
} else {
|
||||
// return false jeśli nie
|
||||
this.getLoggedInName.emit('notLogged');
|
||||
return false;
|
||||
}
|
||||
}).catch((error: any) => Observable.throw(error.json().error || 'Server error'));
|
||||
}
|
||||
|
||||
getToken(): String {
|
||||
const currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
if (currentUser.authorization == null) {
|
||||
return ' ';
|
||||
} else {
|
||||
return currentUser.authorization;
|
||||
}
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
const token: String = this.getToken();
|
||||
return token && token.length > 0;
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
// clear token remove user from local storage to log user out
|
||||
this.snackBar.open('Wylogowano pomyślnie!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-success'] });
|
||||
localStorage.removeItem('currentUser');
|
||||
}
|
||||
}
|
7
src/app/autofocus.directive.spec.ts
Normal file
7
src/app/autofocus.directive.spec.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { AutofocusDirective } from './autofocus.directive';
|
||||
|
||||
describe('AutofocusDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
|
||||
});
|
||||
});
|
15
src/app/autofocus.directive.ts
Normal file
15
src/app/autofocus.directive.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Directive, AfterViewInit, ElementRef } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appAutofocus]'
|
||||
})
|
||||
export class AutofocusDirective implements AfterViewInit {
|
||||
|
||||
constructor(private el: ElementRef) {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.el.nativeElement.focus();
|
||||
}
|
||||
|
||||
}
|
8
src/app/filter-user.pipe.spec.ts
Normal file
8
src/app/filter-user.pipe.spec.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { FilterUserPipe } from './filter-user.pipe';
|
||||
|
||||
describe('FilterUserPipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new FilterUserPipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
20
src/app/filter-user.pipe.ts
Normal file
20
src/app/filter-user.pipe.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'filterUser'
|
||||
})
|
||||
export class FilterUserPipe implements PipeTransform {
|
||||
|
||||
transform(sets: any, searchOwner: any ): any {
|
||||
if (searchOwner === undefined || sets === undefined) {
|
||||
return sets;
|
||||
} else {
|
||||
return sets.filter(function(set){
|
||||
return set.owner.toString() === (searchOwner.toString());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
8
src/app/filter.pipe.spec.ts
Normal file
8
src/app/filter.pipe.spec.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { FilterPipe } from './filter.pipe';
|
||||
|
||||
describe('FilterPipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new FilterPipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
20
src/app/filter.pipe.ts
Normal file
20
src/app/filter.pipe.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'filter'
|
||||
})
|
||||
export class FilterPipe implements PipeTransform {
|
||||
|
||||
transform(sets: any, search: any ): any {
|
||||
if (search === undefined || sets === undefined) {
|
||||
return sets;
|
||||
} else {
|
||||
return sets.filter(function(set){
|
||||
return set.permission === (search);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
.description {
|
||||
background-color: #22272a;
|
||||
padding: 1rem;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper-description {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.wrapper-add {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.content{
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
ag-grid-angular{
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.buttons-container > div{
|
||||
margin: 10px;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<div class="wrapper">
|
||||
<div class="content">
|
||||
<div class="buttons-container">
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets"><i class="fas fa-arrow-left"></i> WRÓĆ DO LISTY</button>
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/add/table"><i class="fas fa-table"></i> DODAJ ZA POMOCĄ TABELI</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper-add">
|
||||
<div class="container">
|
||||
<h1>Importowanie zestawu z pliku CSV</h1>
|
||||
<br />
|
||||
<h3>Twój plik CSV powinien mieć poniższy format:</h3>
|
||||
<div class="wrapper-description">
|
||||
<div class="description row">
|
||||
<h4 class="col-8 ml-4">
|
||||
nazwa zestawu;kategoria <br />
|
||||
lewa strona fiszki;prawa strona fiszki <br />
|
||||
lewa strona fiszki;prawa strona fiszki <br />
|
||||
lewa strona fiszki;prawa strona fiszki <br />
|
||||
.....
|
||||
</h4>
|
||||
<p class="col-3 ml-4">
|
||||
<u>Przykład:</u> <br />
|
||||
zwierzęta;angielski <br />
|
||||
pies;dog <br />
|
||||
kot;cat <br />
|
||||
królik;rabbit <br />
|
||||
ryba;fish <br />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div *ngIf="currentFileUpload" class="progress">
|
||||
<div class="progress-bar progress-bar-info progress-bar-striped"
|
||||
role="progressbar" attr.aria-valuenow="{{progress.percentage}}"
|
||||
aria-valuemin="0" aria-valuemax="100"
|
||||
[ngStyle]="{width:progress.percentage+'%'}">
|
||||
{{progress.percentage}}%</div>
|
||||
</div>
|
||||
<label>
|
||||
<p>Wybierz plik:</p>
|
||||
<input type="file" accept=".csv" (change)="selectFile($event)">
|
||||
</label>
|
||||
<div>
|
||||
<br />
|
||||
<input type="checkbox" name="{{ permission }}" class="form-control" [checked]="permission" (change)="changePermission()"/><b>Udostępnij publicznie</b>
|
||||
</div><br />
|
||||
<button class="btn btn-study-cave" [disabled]="!selectedFiles" (click)="upload()"><i class="fas fa-check-circle"></i> Dodaj fiszki!</button>
|
||||
<br /><br />
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets/"><i class="fas fa-arrow-left"></i> Powrót</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsAddCsvComponent } from './flashcards-add-csv.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsAddCsvComponent', () => {
|
||||
let component: FlashcardsAddCsvComponent;
|
||||
let fixture: ComponentFixture<FlashcardsAddCsvComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsAddCsvComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [HttpClientModule, RouterTestingModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsAddCsvComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,75 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient, HttpResponse, HttpEventType } from '@angular/common/http';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-add-csv',
|
||||
templateUrl: './flashcards-add-csv.component.html',
|
||||
styleUrls: ['./flashcards-add-csv.component.css']
|
||||
})
|
||||
export class FlashcardsAddCsvComponent implements OnInit {
|
||||
|
||||
selectedFiles: FileList;
|
||||
currentFileUpload: File;
|
||||
progress: { percentage: number } = { percentage: 0 };
|
||||
currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
user: string;
|
||||
permission: Boolean = true;
|
||||
constructor(private uploadService: FlashcardsService, private router: Router, public snackBar: MatSnackBar) { }
|
||||
|
||||
ngOnInit() { this.isLoggedIn(); }
|
||||
|
||||
isLoggedIn() {
|
||||
if (localStorage.getItem('currentUser') === null) {
|
||||
this.user = 'Anonim';
|
||||
} else {
|
||||
this.user = this.currentUser.username;
|
||||
}
|
||||
}
|
||||
|
||||
changePermission(): void {
|
||||
this.permission = !this.permission;
|
||||
}
|
||||
|
||||
selectFile(event) {
|
||||
this.selectedFiles = event.target.files;
|
||||
}
|
||||
|
||||
upload() {
|
||||
this.progress.percentage = 0;
|
||||
const url = 'file/upload';
|
||||
let p = 'Private';
|
||||
if (this.permission) {
|
||||
p = 'Public';
|
||||
}
|
||||
this.currentFileUpload = this.selectedFiles.item(0);
|
||||
if (this.currentFileUpload.type === 'application/vnd.ms-excel') {
|
||||
this.uploadService.pushFileToStorage(this.currentFileUpload, this.user, p, url).subscribe(
|
||||
event => {
|
||||
if (event.type === HttpEventType.UploadProgress) {
|
||||
this.progress.percentage = Math.round(100 * event.loaded / event.total);
|
||||
} else if (event instanceof HttpResponse) {
|
||||
this.currentFileUpload = undefined;
|
||||
this.snackBar.open(`Plik został zaimportowany.
|
||||
Swoje fiszki możesz podejrzeć na liście zestawów fiszek
|
||||
i tam je edytować jeśli zajdzie taka potrzeba :)`, null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-success'] });
|
||||
this.router.navigate(['flashcards/sets']);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.snackBar.open('Coś poszło nie tak. Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
this.currentFileUpload = undefined;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.currentFileUpload = undefined;
|
||||
this.snackBar.open('Wybierz plik CSV!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
}
|
||||
this.selectedFiles = undefined;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table, th, td, tr {
|
||||
border-width: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper-add {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.content{
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
ag-grid-angular{
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.buttons-container > div{
|
||||
margin: 10px;
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
<div class="wrapper">
|
||||
<div class="content">
|
||||
<div class="buttons-container">
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets"><i class="fas fa-arrow-left"></i> WRÓĆ DO LISTY</button>
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/add/csv"><i class="fas fa-file-csv"></i> DODAJ ZA POMOCĄ CSV</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper-add">
|
||||
<div class="container">
|
||||
<h1>Tworzenie zestawu</h1>
|
||||
<br />
|
||||
<form ngNativeValidate action="/" method="post" #user="ngForm" (ngSubmit)="addTable(user.value)">
|
||||
<label>
|
||||
Wprowadź nazwę dla zestawu:
|
||||
<input type="text" name="title" class="form-control" ngModel required />
|
||||
</label>
|
||||
<label>
|
||||
Wprowadź kategorię zestawu:
|
||||
<input type="text" name="category" class="form-control" ngModel required />
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
Wypełnij tabelę fiszkami:
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Lewa strona</th>
|
||||
<th>Prawa strona</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let field of fieldArray; let i = index">
|
||||
<td>
|
||||
<input [(ngModel)]="field.left_side" class="form-control" type="text" name="{{field.left_side}}" />
|
||||
</td>
|
||||
<td>
|
||||
<input [(ngModel)]="field.right_side" class="form-control" type="text" name="{{field.right_side}}" />
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-study-cave" type="button" (click)="deleteFieldValue(i)"><i class="fas fa-trash-alt"></i> Usuń fiszkę</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input class="form-control" type="text" id="newAttributeLeft" [(ngModel)]="newAttribute.left_side" name="newAttributeLeft" />
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control" type="text" id="newAttributeRight" [(ngModel)]="newAttribute.right_side" name="newAttributeRight" />
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-study-cave" type="button" (click)="addFieldValue()"><i class="fas fa-plus"></i> Dodaj fiszkę</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</label>
|
||||
<div>
|
||||
<br />
|
||||
<input type="checkbox" name="{{ permission }}" class="form-control" [checked]="permission" (change)="changePermission()"/>
|
||||
<b>Udostępnij publicznie</b>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button class="btn btn-study-cave" type="submit"><i class="fas fa-check-circle"></i> Dodaj fiszki!</button>
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets/"><i class="fas fa-arrow-left"></i> Powrót</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,44 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsAddTableComponent } from './flashcards-add-table.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
describe('FlashcardsAddTableComponent', () => {
|
||||
let component: FlashcardsAddTableComponent;
|
||||
let fixture: ComponentFixture<FlashcardsAddTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsAddTableComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [HttpClientModule, RouterTestingModule, MatSnackBarModule, FormsModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsAddTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
// Testowanie funkcji w klasie
|
||||
it('should change permissions', () => {
|
||||
expect(component.permission).toBe(true);
|
||||
component.changePermission();
|
||||
expect(component.permission).toBe(false);
|
||||
component.changePermission();
|
||||
expect(component.permission).toBe(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,84 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-add-table',
|
||||
templateUrl: './flashcards-add-table.component.html',
|
||||
styleUrls: ['./flashcards-add-table.component.css']
|
||||
})
|
||||
export class FlashcardsAddTableComponent implements OnInit {
|
||||
|
||||
table: Boolean = false;
|
||||
tableToSend: any = {};
|
||||
public fieldArray: Array<any> = [];
|
||||
newAttribute: any = {};
|
||||
currentUser;
|
||||
permission: Boolean = true;
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService, public snackBar: MatSnackBar) { }
|
||||
|
||||
ngOnInit() { this.isLoggedIn(); }
|
||||
|
||||
changePermission(): void {
|
||||
this.permission = !this.permission;
|
||||
}
|
||||
|
||||
isLoggedIn() {
|
||||
if (localStorage.getItem('currentUser') === null) {
|
||||
this.currentUser = 'Anonim';
|
||||
} else {
|
||||
this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
}
|
||||
}
|
||||
|
||||
addFieldValue() {
|
||||
const undefinedAttr = ((this.newAttribute['left_side'] === undefined) || (this.newAttribute['right_side'] === undefined));
|
||||
if (undefinedAttr) {
|
||||
this.snackBar.open('Nie można dodać fiszki z pustym polem!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
} else {
|
||||
const length = ((this.newAttribute['left_side'].trim().length === 0) || (this.newAttribute['right_side'].trim().length === 0));
|
||||
if (length) {
|
||||
this.snackBar.open('Nie można dodać fiszki z pustym polem!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
} else {
|
||||
this.fieldArray.push(this.newAttribute);
|
||||
this.newAttribute = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteFieldValue(index) {
|
||||
this.fieldArray.splice(index, 1);
|
||||
}
|
||||
|
||||
setOwner(): string {
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
return JSON.parse(localStorage.getItem('currentUser')).username;
|
||||
} else {
|
||||
return 'anonim';
|
||||
}
|
||||
}
|
||||
|
||||
addTable(value: any) {
|
||||
// obsługa formularza dodawania fiszek do tabeli
|
||||
if (this.fieldArray.length === 0) {
|
||||
this.snackBar.open('Zestaw fiszek nie może być pusty!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
} else {
|
||||
let p = 'Private';
|
||||
if (this.permission) {
|
||||
p = 'Public';
|
||||
}
|
||||
this.tableToSend = {
|
||||
name: value.title,
|
||||
category: value.category,
|
||||
owner: this.setOwner(),
|
||||
flashcards: this.fieldArray,
|
||||
permission: p
|
||||
};
|
||||
this.flashcardsService.add(this.tableToSend);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
.wrapper{
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.mobile{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.empty{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content{
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
ag-grid-angular{
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.buttons-container > div{
|
||||
margin: 10px;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<div class="wrapper">
|
||||
<div class="content">
|
||||
<div class="buttons-container">
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets"><i class="fas fa-arrow-left"></i> WRÓĆ DO LISTY</button>
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/add/table"><i class="fas fa-table"></i> DODAJ ZA POMOCĄ TABELI</button>
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/add/csv"><i class="fas fa-file-csv"></i> DODAJ ZA POMOCĄ CSV</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsAddComponent } from './flashcards-add.component';
|
||||
|
||||
describe('FlashcardsAddComponent', () => {
|
||||
let component: FlashcardsAddComponent;
|
||||
let fixture: ComponentFixture<FlashcardsAddComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsAddComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsAddComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-add',
|
||||
templateUrl: './flashcards-add.component.html',
|
||||
styleUrls: ['./flashcards-add.component.css']
|
||||
})
|
||||
export class FlashcardsAddComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table, th, td, tr {
|
||||
border-width: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper-add {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.content{
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
ag-grid-angular{
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.buttons-container > div{
|
||||
margin: 10px;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<div class="wrapper">
|
||||
<div class="content">
|
||||
<div class="buttons-container">
|
||||
<button class="btn btn-study-cave" (click)="returnToSet()"><i class="fas fa-arrow-left"></i> WRÓĆ DO ZESTAWU</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper-add">
|
||||
<div class="container">
|
||||
<h1>Edycja zestawu</h1>
|
||||
<br />
|
||||
<form ngNativeValidate action="/" method="post" #user="ngForm" (ngSubmit)="addTable(user.value)">
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<label>
|
||||
Wprowadź nazwę dla zestawu:
|
||||
<input type="text" name="title" class="form-control" [(ngModel)]="set['name']" required />
|
||||
</label>
|
||||
<label>
|
||||
Wprowadź kategorię zestawu:
|
||||
<input type="text" name="category" class="form-control" [(ngModel)]="set['category']" required />
|
||||
</label>
|
||||
</div>
|
||||
<label class="col-md-2">
|
||||
<br />
|
||||
<input type="checkbox" name="{{ permission }}" class="form-control" [checked]="permission" (change)="changePermission()"/>
|
||||
<b>Udostępnij publicznie</b>
|
||||
</label>
|
||||
</div>
|
||||
<br />
|
||||
<label>
|
||||
Wypełnij tabelę fiszkami:
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Lewa strona</th>
|
||||
<th>Prawa strona</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let field of fieldArray; let i = index">
|
||||
<td>
|
||||
<input [(ngModel)]="field.left_side" class="form-control" type="text" name="{{field.left_side}}" />
|
||||
</td>
|
||||
<td>
|
||||
<input [(ngModel)]="field.right_side" class="form-control" type="text" name="{{field.right_side}}" />
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-study-cave" type="button" (click)="deleteFieldValue(i)"><i class="fas fa-trash-alt"></i> Usuń fiszkę</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input class="form-control" type="text" id="newAttributeLeft" [(ngModel)]="newAttribute['left_side']" name="newAttributeLeft" />
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control" type="text" id="newAttributeRight" [(ngModel)]="newAttribute['right_side']" name="newAttributeRight" />
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-study-cave" type="button" (click)="addFieldValue()"><i class="fas fa-file-csv"></i> Dodaj fiszkę</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</label>
|
||||
<br />
|
||||
<div>
|
||||
<button class="btn btn-study-cave" type="submit"><i class="fas fa-check-circle"></i> Edytuj fiszki!</button>
|
||||
<button class="btn btn-study-cave" [routerLink]="['/flashcards/sets', ident]"><i class="fas fa-arrow-left"></i> Powrót</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,35 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsEditTableComponent } from './flashcards-edit-table.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsEditTableComponent', () => {
|
||||
let component: FlashcardsEditTableComponent;
|
||||
let fixture: ComponentFixture<FlashcardsEditTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsEditTableComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsEditTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,106 @@
|
||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-edit-table',
|
||||
templateUrl: './flashcards-edit-table.component.html',
|
||||
styleUrls: ['./flashcards-edit-table.component.css']
|
||||
})
|
||||
export class FlashcardsEditTableComponent implements OnInit, OnDestroy {
|
||||
|
||||
ident: number;
|
||||
permission: Boolean = false;
|
||||
table: Boolean = false;
|
||||
tableToSend: any = {};
|
||||
fieldArray: Array<any> = [];
|
||||
newAttribute: any = {};
|
||||
set: Object = {};
|
||||
flashcardSubscribtion: Subscription;
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService, private route: ActivatedRoute, private router: Router,
|
||||
public snackBar: MatSnackBar) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.ident = this.route.snapshot.params.id;
|
||||
this.flashcardSubscribtion = this.flashcardsService.getSet(this.ident).subscribe(data => {
|
||||
this.set = data;
|
||||
if (data['permission'] === 'Private') {
|
||||
this.permission = false;
|
||||
} else {
|
||||
this.permission = true;
|
||||
}
|
||||
const flashcards = data['flashcards'];
|
||||
for (let i = 0; i < flashcards.length; i++) {
|
||||
const id = flashcards[i]['id'];
|
||||
this.fieldArray.push({
|
||||
id: id,
|
||||
left_side: flashcards[i]['left_side'],
|
||||
right_side: flashcards[i]['right_side']
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
returnToSet() {
|
||||
this.router.navigate(['/flashcards/sets/', this.ident]);
|
||||
}
|
||||
addFieldValue() {
|
||||
const undefinedAttr = ((this.newAttribute['left_side'] === undefined) || (this.newAttribute['right_side'] === undefined));
|
||||
if (undefinedAttr) {
|
||||
this.snackBar.open('Nie można dodać fiszki z pustym polem!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
} else {
|
||||
const length = ((this.newAttribute['left_side'].trim().length === 0) || (this.newAttribute['right_side'].trim().length === 0));
|
||||
if (length) {
|
||||
this.snackBar.open('Nie można dodać fiszki z pustym polem!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
} else {
|
||||
const insert = {
|
||||
id: null,
|
||||
left_side: this.newAttribute['left_side'],
|
||||
right_side: this.newAttribute['right_side'],
|
||||
};
|
||||
this.fieldArray.push(insert);
|
||||
this.newAttribute = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteFieldValue(index) {
|
||||
this.fieldArray.splice(index, 1);
|
||||
}
|
||||
|
||||
addTable(value: any) {
|
||||
const currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
if (this.fieldArray.length === 0) {
|
||||
this.snackBar.open('Zestaw fiszek nie może być pusty!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
} else {
|
||||
let perm = 'Private';
|
||||
if (this.permission) {
|
||||
perm = 'Public';
|
||||
}
|
||||
this.tableToSend = {
|
||||
id: this.ident,
|
||||
name: value.title,
|
||||
permission: perm,
|
||||
category: value.category,
|
||||
owner: currentUser.username,
|
||||
flashcards: this.fieldArray
|
||||
};
|
||||
this.flashcardsService.edit(this.tableToSend);
|
||||
}
|
||||
}
|
||||
|
||||
changePermission(): void {
|
||||
this.permission = !this.permission;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.flashcardSubscribtion.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
#container-small {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 32%;
|
||||
height: 400px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#container-large {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 62%;
|
||||
min-height: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.content {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#container-small {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
#container-small, #container-large {
|
||||
width: 90%;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<div class="content">
|
||||
<div id="container-small">
|
||||
<h4>Uzupełnianie fiszek</h4>
|
||||
<br />
|
||||
<div>
|
||||
<b>Nazwa zestawu: </b>
|
||||
<i>{{ name }}</i>
|
||||
<br />
|
||||
<b>Kategoria: </b>
|
||||
<i>{{ category }}</i>
|
||||
</div>
|
||||
<div *ngIf="started">
|
||||
<div>
|
||||
<div>
|
||||
<b>Uzupełniono: </b>
|
||||
<span> {{ filled }} z {{ length_test }} fiszek</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Poprawnych odpowiedzi: </b>
|
||||
<span> {{ good }} na {{ length_test }}</span><br />
|
||||
<b>Złych odpowiedzi: </b>
|
||||
<span> {{ bad }} na {{ length_test }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-large">
|
||||
<div *ngIf="started">
|
||||
<div *ngIf="this.filled >= 1 && !finish">
|
||||
|
||||
Poprzednia odpowiedź:<br />
|
||||
{{flashcards[index-1].content}} {{allAnswers[index-1].answer}}
|
||||
</div>
|
||||
<div *ngIf="this.filled < this.length_test && !finish ">
|
||||
Podaj odpowiedź:<br />
|
||||
{{flashcards[index].content}}
|
||||
<input appAutofocus [(ngModel)]="answer" class="mr-2" placeholder="odpowiedź" (keyup.enter)="verifyAnswer()" >
|
||||
<button class="btn btn-study-cave" (click)="verifyAnswer()"><i class="fas fa-check-circle"></i> Sprawdź</button>
|
||||
</div>
|
||||
<div *ngIf="this.is_correct === true && !finish">ODPOWIEDŹ POPRAWNA</div>
|
||||
<div *ngIf="this.is_correct === false && !finish">ODPOWIEDŹ NIEPOPRAWNA</div>
|
||||
<div *ngIf="this.filled < this.length_test-1 && !finish">
|
||||
Następne pytanie:<br />
|
||||
{{flashcards[index+1].content}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div *ngIf="finish">
|
||||
<app-test-results [result]="good" [maxPts]="length_test"></app-test-results>
|
||||
</div>
|
||||
<div *ngIf="!finish">
|
||||
<button class="btn btn-study-cave" *ngIf="!started" (click)="start()"><i class="far fa-play-circle"></i> Rozpocznij test</button>
|
||||
</div>
|
||||
<button class="btn btn-study-cave" *ngIf="finish" routerLink="/flashcards/sets/{{ id }}"><i class="far fa-stop-circle"></i> Zakończ test</button>
|
||||
<button class="btn btn-study-cave" *ngIf="started && !finish && !not_last"(click)="finished()"><i class="fas fa-arrow-left"></i> Przejdź do wyniku</button>
|
||||
<br />
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets/{{ id }}"><i class="fas fa-arrow-left"></i> Wróć do zestawu</button>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsFillingInTestComponent } from './flashcards-filling-in-test.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsFillingInTestComponent', () => {
|
||||
let component: FlashcardsFillingInTestComponent;
|
||||
let fixture: ComponentFixture<FlashcardsFillingInTestComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsFillingInTestComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsFillingInTestComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,96 @@
|
||||
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-filling-in-test',
|
||||
templateUrl: './flashcards-filling-in-test.component.html',
|
||||
styleUrls: ['./flashcards-filling-in-test.component.css']
|
||||
})
|
||||
export class FlashcardsFillingInTestComponent implements OnInit, OnDestroy {
|
||||
|
||||
id: number;
|
||||
flashcardSubscribtionMeta: Subscription;
|
||||
flashcardSubscribtion: Subscription;
|
||||
flashcardSubscribtionCheck: Subscription;
|
||||
name: String;
|
||||
category: String;
|
||||
length_test: number;
|
||||
goodNow: number;
|
||||
started: Boolean = false;
|
||||
finish: Boolean = false;
|
||||
flashcards: Array<Object> = [];
|
||||
filled = 0;
|
||||
good = 0;
|
||||
bad = 0;
|
||||
answer: String;
|
||||
index = 0;
|
||||
not_last: Boolean = true;
|
||||
is_correct: Boolean;
|
||||
allAnswers = [];
|
||||
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService, private route: ActivatedRoute) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.id = this.route.snapshot.params.id;
|
||||
this.flashcardSubscribtionMeta = this.flashcardsService.getSet(this.id).subscribe(data => {
|
||||
this.name = data['name'];
|
||||
this.category = data['category'];
|
||||
});
|
||||
this.flashcardSubscribtion = this.flashcardsService.getTestFilling(this.id).subscribe(data => {
|
||||
this.length_test = data.length;
|
||||
this.flashcards = data;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
start() {
|
||||
this.started = true;
|
||||
}
|
||||
finished() {
|
||||
this.finish = true;
|
||||
}
|
||||
verifyAnswer() {
|
||||
const body = [];
|
||||
const n = this.length_test;
|
||||
if (this.answer === '') {
|
||||
this.answer = ' ';
|
||||
}
|
||||
this.allAnswers.push({
|
||||
id: this.index,
|
||||
answer: this.answer,
|
||||
});
|
||||
body.push({
|
||||
id: this.flashcards[this.index]['id'],
|
||||
content: this.answer,
|
||||
side: this.flashcards[this.index]['side'],
|
||||
});
|
||||
this.flashcardSubscribtionCheck = this.flashcardsService.testCheck(this.id, body[0])
|
||||
.subscribe(data => {
|
||||
this.is_correct = data.result;
|
||||
if (this.is_correct === true) {
|
||||
this.good = this.good + 1;
|
||||
} else {
|
||||
this.bad = this.bad + 1;
|
||||
}
|
||||
});
|
||||
if (this.index < this.length_test) {
|
||||
this.index = this.index + 1;
|
||||
this.filled = this.filled + 1;
|
||||
this.answer = '';
|
||||
}
|
||||
if (this.index === this.length_test) {
|
||||
this.not_last = false;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.flashcardSubscribtionMeta.unsubscribe();
|
||||
this.flashcardSubscribtion.unsubscribe();
|
||||
if (this.flashcardSubscribtionCheck) {
|
||||
this.flashcardSubscribtionCheck.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card {
|
||||
color: white;
|
||||
background-color: gray;
|
||||
text-align: center;
|
||||
min-height: 4rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
transition: color 1000ms;
|
||||
}
|
||||
|
||||
.card-invisible {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.card-visible {
|
||||
font-size: 1.5rem;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<div class="container">
|
||||
<div>
|
||||
<h2 *ngIf="!isOK && !isBad"> </h2>
|
||||
<h2 *ngIf="isOK">Dobrze :)</h2>
|
||||
<h2 *ngIf="isBad">Źle :(</h2>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row">
|
||||
<div *ngFor="let card of set; let i = index" class="col-md-6">
|
||||
<p *ngIf="!visible[i]" id="{{ i }}" class="card card-invisible clickable" (click)="check($event)">???</p>
|
||||
<p *ngIf="visible[i]" id="{{ i }}" class='card card-visible unclickable' onclick='return false;'><b>{{ card }}</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsMemoryTestSetComponent } from './flashcards-memory-test-set.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsMemoryTestSetComponent', () => {
|
||||
let component: FlashcardsMemoryTestSetComponent;
|
||||
let fixture: ComponentFixture<FlashcardsMemoryTestSetComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsMemoryTestSetComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsMemoryTestSetComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,121 @@
|
||||
import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-memory-test-set',
|
||||
templateUrl: './flashcards-memory-test-set.component.html',
|
||||
styleUrls: ['./flashcards-memory-test-set.component.css']
|
||||
})
|
||||
export class FlashcardsMemoryTestSetComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
@Input() package: Array<any>;
|
||||
@Input() id: number;
|
||||
@Input() package_id: number;
|
||||
|
||||
@Output() goodEvent = new EventEmitter();
|
||||
@Output() isChecked = new EventEmitter();
|
||||
|
||||
flashcardSubscribtion: Array<Subscription> = [];
|
||||
answer: Array<Object> = [];
|
||||
set: Array<Object> = [];
|
||||
visible: Array<Boolean> = [];
|
||||
toCheck: Array<number> = [];
|
||||
isBad: Boolean = false;
|
||||
isOK: Boolean = false;
|
||||
good = 0;
|
||||
clicks = 0;
|
||||
|
||||
constructor(private uploadService: FlashcardsService, public snackBar: MatSnackBar) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.isChecked.emit(false);
|
||||
this.flashcardSubscribtion = [];
|
||||
this.visible = [];
|
||||
this.set = this.package[this.package_id]['set'];
|
||||
for (let i = 0; i < this.set.length; i++) {
|
||||
this.visible.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.ngOnDestroy();
|
||||
const package_idChanges = changes['package_id'];
|
||||
if (package_idChanges) {
|
||||
this.ngOnInit();
|
||||
}
|
||||
}
|
||||
|
||||
check(event) {
|
||||
if (this.clicks <= 2) {
|
||||
this.clicks += 1;
|
||||
this.toCheck.push(event.target.id);
|
||||
this.visible[this.toCheck[0]] = true;
|
||||
if (this.clicks === 2) {
|
||||
this.visible[this.toCheck[1]] = true;
|
||||
const toSend = {
|
||||
x: this.set[this.toCheck[0]],
|
||||
y: this.set[this.toCheck[1]],
|
||||
};
|
||||
setTimeout(() => {
|
||||
this.flashcardSubscribtion[this.flashcardSubscribtion.length] =
|
||||
this.uploadService.testMemory(this.id, toSend).subscribe(data => {
|
||||
this.showWrong(data);
|
||||
this.clicks = 0;
|
||||
},
|
||||
error => {
|
||||
this.snackBar.open('Coś poszło nie tak :( Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
this.clicks = 0;
|
||||
}
|
||||
);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showWrong(answer: Boolean) {
|
||||
this.isGood(answer);
|
||||
this.goodEvent.emit(this.good);
|
||||
}
|
||||
|
||||
isGood(answer: Boolean) {
|
||||
if (!answer) {
|
||||
this.isBad = true;
|
||||
this.visible[this.toCheck[0]] = false;
|
||||
this.visible[this.toCheck[1]] = false;
|
||||
setTimeout(() => {
|
||||
this.isBad = false;
|
||||
}, 1000);
|
||||
} else {
|
||||
this.isOK = true;
|
||||
this.visible[this.toCheck[0]] = true;
|
||||
this.visible[this.toCheck[1]] = true;
|
||||
document.getElementById(this.toCheck[0].toString()).style.color = 'rgb(94, 249, 37)';
|
||||
document.getElementById(this.toCheck[1].toString()).style.color = 'rgb(94, 249, 37)';
|
||||
setTimeout(() => {
|
||||
this.isOK = false;
|
||||
}, 1000);
|
||||
this.good += 1;
|
||||
let i = 0;
|
||||
while (this.visible[i]) {
|
||||
if (i === (this.visible.length - 1)) {
|
||||
this.isChecked.emit(true);
|
||||
}
|
||||
i++;
|
||||
if (i === this.visible.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.toCheck = [];
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
for (let i = 0; i < this.flashcardSubscribtion.length; i++) {
|
||||
this.flashcardSubscribtion[i].unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
#container-small {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 32%;
|
||||
height: 400px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#container-large {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 62%;
|
||||
min-height: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.content {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#container-small {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
#container-small, #container-large {
|
||||
width: 90%;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<div id="container-small">
|
||||
<h4>Memory</h4>
|
||||
<br />
|
||||
<div>
|
||||
<b>Nazwa zestawu: </b>
|
||||
<i>{{ name }}</i>
|
||||
<br />
|
||||
<b>Kategoria: </b>
|
||||
<i>{{ category }}</i>
|
||||
</div>
|
||||
<div *ngIf="started">
|
||||
<div>
|
||||
<div>
|
||||
<b>Uzupełniono: </b>
|
||||
<span> {{ filled }} z {{ flashcards }} fiszek</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Poprawnych odpowiedzi: </b>
|
||||
<span> {{ good }} na {{ flashcards }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-large">
|
||||
<div class="test" *ngIf="started">
|
||||
<app-flashcards-memory-test-set (goodEvent)="goodEvent($event)" (isChecked)=isChecked($event)
|
||||
[package]="packages" package_id="{{ package_id }}" [id]="id"></app-flashcards-memory-test-set>
|
||||
<br />
|
||||
<div>
|
||||
<b>Ekran: </b>
|
||||
<span> {{ package_id + 1 }} z {{ length_packages }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="finish">
|
||||
<app-test-results [result]="good" [maxPts]="flashcards"></app-test-results>
|
||||
</div>
|
||||
<br />
|
||||
<div *ngIf="!finish">
|
||||
<button class="btn btn-study-cave" *ngIf="!started" (click)="start()"><i class="far fa-play-circle"></i> Rozpocznij test</button>
|
||||
<button class="btn btn-study-cave" *ngIf="checked && not_last" (click)="increment()"><i class="fas fa-arrow-right"></i>Przejdź dalej</button>
|
||||
<button class="btn btn-study-cave" *ngIf="checked && !not_last" (click)="increment()"><i class="far fa-stop-circle"></i> Zakończ test</button>
|
||||
</div>
|
||||
<br />
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets/{{ id }}"><i class="fas fa-arrow-left"></i> Wróć do zestawu</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsMemoryTestComponent } from './flashcards-memory-test.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsMemoryTestComponent', () => {
|
||||
let component: FlashcardsMemoryTestComponent;
|
||||
let fixture: ComponentFixture<FlashcardsMemoryTestComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsMemoryTestComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsMemoryTestComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,102 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-memory-test',
|
||||
templateUrl: './flashcards-memory-test.component.html',
|
||||
styleUrls: ['./flashcards-memory-test.component.css']
|
||||
})
|
||||
export class FlashcardsMemoryTestComponent implements OnInit, OnDestroy {
|
||||
|
||||
id: number;
|
||||
flashcardSubscribtionMeta: Subscription;
|
||||
flashcardSubscribtion: Subscription;
|
||||
name: String;
|
||||
category: String;
|
||||
length_test: number;
|
||||
flashcards: number;
|
||||
length_packages: number;
|
||||
goodNow: number;
|
||||
started: Boolean = false;
|
||||
finish: Boolean = false;
|
||||
checked: Boolean = false;
|
||||
not_last: Boolean = true;
|
||||
packages: Array<Object> = [];
|
||||
filled = 0;
|
||||
good = 0;
|
||||
package_id = 0;
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService, private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.id = this.route.snapshot.params.id;
|
||||
this.flashcardSubscribtionMeta = this.flashcardsService.getSet(this.id).subscribe(data => {
|
||||
this.name = data['name'];
|
||||
this.category = data['category'];
|
||||
});
|
||||
this.flashcardSubscribtion = this.flashcardsService.getTestMemory(this.id).subscribe(data => {
|
||||
this.length_test = data.length;
|
||||
this.flashcards = data.length / 2;
|
||||
this.createPackages(data);
|
||||
});
|
||||
}
|
||||
|
||||
createPackages(data) {
|
||||
let attribute = '0';
|
||||
let set = [];
|
||||
const n = this.length_test;
|
||||
for (let i = 0; i < n; i++) {
|
||||
if (i % 10 === 0) {
|
||||
this.packages[attribute] = {
|
||||
set: set,
|
||||
};
|
||||
attribute = (i / 10).toString();
|
||||
set = [];
|
||||
}
|
||||
set.push(data[i]);
|
||||
if (i === (n - 1)) {
|
||||
this.packages[attribute] = {
|
||||
set: set,
|
||||
};
|
||||
}
|
||||
}
|
||||
this.length_packages = this.packages.length;
|
||||
if (this.packages.length < 2) {
|
||||
this.not_last = false;
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
increment() {
|
||||
if (this.package_id === (this.length_packages - 2)) {
|
||||
this.not_last = false;
|
||||
}
|
||||
if (this.package_id === (this.length_packages - 1)) {
|
||||
this.started = false;
|
||||
this.finish = true;
|
||||
} else {
|
||||
this.package_id += 1;
|
||||
}
|
||||
}
|
||||
|
||||
goodEvent(goods) {
|
||||
this.goodNow = goods;
|
||||
this.filled = this.goodNow;
|
||||
this.good = this.goodNow;
|
||||
}
|
||||
|
||||
isChecked(check) {
|
||||
this.checked = check;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.flashcardSubscribtionMeta.unsubscribe();
|
||||
this.flashcardSubscribtion.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
#container-small {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 25%;
|
||||
height: 400px;
|
||||
margin: 25px;
|
||||
float:left;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
.content{
|
||||
position:fixed;
|
||||
width:100%;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
}
|
||||
#container-large {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 65%;
|
||||
height: 400px;
|
||||
margin: 25px;
|
||||
float: right;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title{
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
.text-content{
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.puzzle{
|
||||
display: flex;
|
||||
min-height: 50px;
|
||||
min-width: 100px;
|
||||
background-color: rgb(206, 168, 86);
|
||||
color: black;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 5px 0 5px 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.puzzle-right{
|
||||
display: flex;
|
||||
color: black;
|
||||
min-height: 50px;
|
||||
min-width: 100px;
|
||||
background-color: rgb(202, 144, 17);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 5px 5px 5px 0;
|
||||
}
|
||||
|
||||
.both-sides{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.puzzle:hover{
|
||||
border: 3px solid gray;
|
||||
}
|
||||
|
||||
.active{
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
.puzzles-container{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.empty{
|
||||
background-color: gray;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.good{
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.wrong{
|
||||
background-color: red;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<div>
|
||||
<h3>Dostępne lewe strony:</h3>
|
||||
<div class="puzzles-container">
|
||||
<div class='puzzle' *ngFor="let item of leftSides; let i = index" (click)="leftSideClick(item,i)" [ngClass]="{'active': (selectedLeftSide.leftSideText === item && selectedLeftSide.indexOfLeftSide === i && selectedLeftSide.from === 'leftSides'), 'empty': (item === undefined || item === '')}">
|
||||
<span>{{item.left_side}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Twoja odpowiedź:</h3>
|
||||
<div class="puzzles-container">
|
||||
<div *ngFor="let item of leftSidesToSend; let i = index" class="both-sides">
|
||||
<div class="puzzle good" *ngIf="result[i] && verify">
|
||||
<span>{{item.left_side}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="puzzle wrong" *ngIf="!result[i] && verify">
|
||||
<span>{{item.left_side}}
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="!verify" class='puzzle' (click)="leftSideToSendClick(item,i)" [ngClass]="{'active': (selectedLeftSide.leftSideText === item && selectedLeftSide.indexOfLeftSide === i && selectedLeftSide.from === 'leftSidesToSend')}">
|
||||
<span>{{item.left_side}}
|
||||
</span>
|
||||
</div>
|
||||
<div class='puzzle-right'>
|
||||
<span>{{rightSides[i].right_side}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br />
|
||||
<button *ngIf="!verify" class="btn btn-study-cave" (click)="nextQuestion()"><i class="fas fa-check-circle"></i> Sprawdź</button>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsPairsTestSetComponent } from './flashcards-pairs-test-set.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsPairsTestSetComponent', () => {
|
||||
let component: FlashcardsPairsTestSetComponent;
|
||||
let fixture: ComponentFixture<FlashcardsPairsTestSetComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsPairsTestSetComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsPairsTestSetComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,121 @@
|
||||
import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import * as $ from 'jquery';
|
||||
import { ISubscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-pairs-test-set',
|
||||
templateUrl: './flashcards-pairs-test-set.component.html',
|
||||
styleUrls: ['./flashcards-pairs-test-set.component.css']
|
||||
})
|
||||
export class FlashcardsPairsTestSetComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
@Input() package: Array<any>;
|
||||
@Input() id: number;
|
||||
@Input() package_id: number;
|
||||
|
||||
@Output() goodEvent = new EventEmitter();
|
||||
@Output() isChecked = new EventEmitter();
|
||||
|
||||
private verifyAnswerSubscription: ISubscription;
|
||||
leftSides = [];
|
||||
rightSides = [];
|
||||
leftSidesToSend = [];
|
||||
result = [];
|
||||
verify = false;
|
||||
good = 0;
|
||||
selectedLeftSide = { indexOfLeftSide: Number, left_side: String, from: '', id: Number };
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.isChecked.emit(false);
|
||||
this.prepareLists();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.prepareLists();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.verifyAnswerSubscription) {
|
||||
this.verifyAnswerSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
nextQuestion(f) {
|
||||
let canSend = true;
|
||||
this.good = 0;
|
||||
this.result = [];
|
||||
this.leftSides.forEach(element => {
|
||||
if (element !== '') {
|
||||
canSend = false;
|
||||
}
|
||||
});
|
||||
if (canSend) {
|
||||
this.verify = true;
|
||||
this.leftSidesToSend.forEach((element, index) => {
|
||||
const body = {
|
||||
content: this.rightSides[index].right_side,
|
||||
id: element.id,
|
||||
side: 'left'
|
||||
};
|
||||
this.verifyAnswerSubscription = this.flashcardsService.testCheck(this.id, body).subscribe(d => {
|
||||
this.result[index] = d.result;
|
||||
if (d.result) {
|
||||
this.good += 1;
|
||||
}
|
||||
if (this.result.length === this.leftSidesToSend.length) {
|
||||
this.send();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
send() {
|
||||
this.isChecked.emit(true);
|
||||
this.goodEvent.emit(this.good);
|
||||
}
|
||||
|
||||
leftSideClick(item, i) {
|
||||
if (item !== '' && item !== undefined) {
|
||||
if (this.selectedLeftSide.from === 'leftSides') {
|
||||
this.selectedLeftSide = { indexOfLeftSide: undefined, left_side: undefined, from: undefined, id: undefined };
|
||||
} else {
|
||||
this.selectedLeftSide = { indexOfLeftSide: i, left_side: item.left_side, from: 'leftSides', id: item.id };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leftSideToSendClick(item, i) {
|
||||
if (this.selectedLeftSide.from === 'leftSides') {
|
||||
const helper = this.leftSidesToSend[i];
|
||||
this.leftSidesToSend[i] = this.selectedLeftSide;
|
||||
this.leftSides[Number(this.selectedLeftSide.indexOfLeftSide)] = helper;
|
||||
this.selectedLeftSide = { indexOfLeftSide: undefined, left_side: undefined, from: undefined, id: undefined };
|
||||
} else if (this.selectedLeftSide.from === 'leftSidesToSend') {
|
||||
const helper = this.leftSidesToSend[i];
|
||||
this.leftSidesToSend[i] = this.selectedLeftSide;
|
||||
this.leftSidesToSend[Number(this.selectedLeftSide.indexOfLeftSide)] = helper;
|
||||
this.selectedLeftSide = { indexOfLeftSide: undefined, left_side: undefined, from: undefined, id: undefined };
|
||||
} else if (item !== '' && item !== undefined) {
|
||||
this.selectedLeftSide = { indexOfLeftSide: i, left_side: item.left_side, from: 'leftSidesToSend', id: item.id };
|
||||
}
|
||||
}
|
||||
|
||||
prepareLists() {
|
||||
this.selectedLeftSide = { indexOfLeftSide: undefined, left_side: undefined, from: undefined, id: undefined };
|
||||
this.leftSides = [];
|
||||
this.rightSides = [];
|
||||
this.leftSidesToSend = [];
|
||||
this.verify = false;
|
||||
this.leftSides = JSON.parse(JSON.stringify(this.package[0].setLeft));
|
||||
this.rightSides = JSON.parse(JSON.stringify(this.package[0].setRight));
|
||||
this.leftSides.forEach(element => {
|
||||
this.leftSidesToSend.push('');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
#container-small {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 32%;
|
||||
height: 400px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#container-large {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 62%;
|
||||
min-height: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.content {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#container-small {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
#container-small, #container-large {
|
||||
width: 90%;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 350px) {
|
||||
|
||||
#container-small {
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
<div class="content">
|
||||
<div id="container-small">
|
||||
<h4>Łączenie fiszek w pary</h4>
|
||||
<br />
|
||||
<div>
|
||||
<b>Nazwa zestawu: </b>
|
||||
<i>{{ name }}</i>
|
||||
<br />
|
||||
<b>Kategoria: </b>
|
||||
<i>{{ category }}</i>
|
||||
</div>
|
||||
<div *ngIf="started">
|
||||
<div>
|
||||
<div>
|
||||
<b>Uzupełniono: </b>
|
||||
<span> {{ filled }} z {{ length_test }} fiszek</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Poprawnych odpowiedzi: </b>
|
||||
<span> {{ good }} na {{ length_test }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Złych odpowiedzi: </b>
|
||||
<span> {{ bad }} na {{ length_test }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-large">
|
||||
<div class="test" *ngIf="started">
|
||||
<app-flashcards-pairs-test-set (goodEvent)="goodEvent($event)" (isChecked)=isChecked($event)
|
||||
[package]="packages" package_id="{{ package_id }}" [id]="id"></app-flashcards-pairs-test-set>
|
||||
<br />
|
||||
<div>
|
||||
<b>Ekran: </b>
|
||||
<span> {{ package_id + 1}} z {{ length_packages }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div *ngIf="finish">
|
||||
<app-test-results [result]="good" [maxPts]="length_test"></app-test-results>
|
||||
</div>
|
||||
<br />
|
||||
<div *ngIf="!finish">
|
||||
<button class="btn btn-study-cave" *ngIf="!started" (click)="start()"><i class="far fa-play-circle"></i> Rozpocznij test</button>
|
||||
<button class="btn btn-study-cave" *ngIf="checked && not_last" (click)="increment()"><i class="far fa-play-circle"></i> Przejdź dalej</button>
|
||||
<button class="btn btn-study-cave" *ngIf="checked && !not_last" (click)="increment()"><i class="far fa-stop-circle"></i> Zakończ test</button>
|
||||
</div>
|
||||
<br />
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets/{{ id }}"><i class="fas fa-arrow-left"></i> Wróć do zestawu</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsPairsTestComponent } from './flashcards-pairs-test.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsPairsTestComponent', () => {
|
||||
let component: FlashcardsPairsTestComponent;
|
||||
let fixture: ComponentFixture<FlashcardsPairsTestComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsPairsTestComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsPairsTestComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,110 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-pairs-test',
|
||||
templateUrl: './flashcards-pairs-test.component.html',
|
||||
styleUrls: ['./flashcards-pairs-test.component.css']
|
||||
})
|
||||
export class FlashcardsPairsTestComponent implements OnInit, OnDestroy {
|
||||
|
||||
id: number;
|
||||
flashcardSubscribtionMeta: Subscription;
|
||||
flashcardSubscribtion: Subscription;
|
||||
name: String;
|
||||
category: String;
|
||||
length_test: number;
|
||||
length_packages: number;
|
||||
goodNow: number;
|
||||
started: Boolean = false;
|
||||
finish: Boolean = false;
|
||||
left: Boolean = true;
|
||||
right: Boolean = false;
|
||||
checked: Boolean = false;
|
||||
not_last: Boolean = true;
|
||||
packages: Array<Object> = [];
|
||||
filled = 0;
|
||||
good = 0;
|
||||
bad = 0;
|
||||
package_id = 0;
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService, private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.id = this.route.snapshot.params.id;
|
||||
this.flashcardSubscribtionMeta = this.flashcardsService.getSet(this.id).subscribe(data => {
|
||||
this.name = data['name'];
|
||||
this.category = data['category'];
|
||||
});
|
||||
this.flashcardSubscribtion = this.flashcardsService.getTestPairing(this.id).subscribe(data => {
|
||||
this.length_test = data['left'].length;
|
||||
this.createPackages(data);
|
||||
});
|
||||
}
|
||||
|
||||
createPackages(data) {
|
||||
let attribute = '0';
|
||||
let setLeft = [];
|
||||
let setRight = [];
|
||||
const n = this.length_test;
|
||||
for (let i = 0; i < n; i++) {
|
||||
if (i % 5 === 0) {
|
||||
this.packages[attribute] = {
|
||||
setLeft: setLeft,
|
||||
setRight: setRight
|
||||
};
|
||||
attribute = (i / 5).toString();
|
||||
setLeft = [];
|
||||
setRight = [];
|
||||
}
|
||||
setLeft.push(data['left'][i]);
|
||||
setRight.push(data['right'][i]);
|
||||
if (i === (n - 1)) {
|
||||
this.packages[attribute] = {
|
||||
setLeft: setLeft,
|
||||
setRight: setRight
|
||||
};
|
||||
}
|
||||
}
|
||||
this.length_packages = this.packages.length;
|
||||
if (this.packages.length < 2) {
|
||||
this.not_last = false;
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
increment() {
|
||||
if (this.package_id === (this.length_packages - 2)) {
|
||||
this.not_last = false;
|
||||
}
|
||||
if (this.package_id === (this.length_packages - 1)) {
|
||||
this.started = false;
|
||||
this.finish = true;
|
||||
} else {
|
||||
this.package_id += 1;
|
||||
}
|
||||
}
|
||||
|
||||
goodEvent(goods) {
|
||||
this.goodNow = goods;
|
||||
const filledNow = this.packages[this.package_id]['setLeft'].length;
|
||||
this.filled = filledNow;
|
||||
this.good = this.goodNow;
|
||||
this.bad = this.filled - this.good;
|
||||
}
|
||||
|
||||
isChecked(check) {
|
||||
this.checked = check;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.flashcardSubscribtionMeta.unsubscribe();
|
||||
this.flashcardSubscribtion.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
.listItem:hover {
|
||||
background-color: rgb(206, 168, 86);
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.btn{
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.content{
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.buttons-container > div{
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.puzzle{
|
||||
min-height: 50px;
|
||||
min-width: 100px;
|
||||
background-color: rgb(206, 168, 86);
|
||||
align-items: center;
|
||||
color: black;
|
||||
justify-content: center;
|
||||
margin: 5px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.puzzle-right{
|
||||
min-height: 50px;
|
||||
min-width: 100px;
|
||||
color: black;
|
||||
background-color: rgb(202, 144, 17);;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 5px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.both-sides{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.puzzles-container{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.empty{
|
||||
background-color: gray;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
<div class="wrapper">
|
||||
<div class="content">
|
||||
<div class="button-container">
|
||||
<button class="btn btn-study-cave" (click)="goBack()"><i class="fas fa-arrow-left"></i> POWRÓT</button>
|
||||
<button class="btn btn-study-cave" (click)="showTestTypeMenu()"><i class="fas fa-pencil-ruler"></i> GENERUJ TESTY</button>
|
||||
<button *ngIf="owned && set && set.permission !== 'GROUP'" class="btn btn-study-cave" (click)="navigateToEditMode()"><i class="fas fa-edit"></i> EDYTUJ FISZKI</button>
|
||||
<button *ngIf="owned && set && set.permission !== 'GROUP'" class="btn btn-study-cave" (click)="showPopup()"><i class="fas fa-trash-alt"></i> USUŃ FISZKI</button>
|
||||
<div *ngIf="user && owned && set && set.permission !== 'GROUP'">
|
||||
<button class="btn btn-study-cave" (click)="changePermission()"><i class="fas fa-unlock"></i> ZMIEŃ UPRAWNIENIA</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-flashcards-test-type-menu [id]="id" (cancel)="handleCancelFlashcardsTestyTypeMenu($event)" *ngIf="testTypeMenu"></app-flashcards-test-type-menu>
|
||||
<br />
|
||||
<div *ngIf="set">
|
||||
<h2>{{set.name}}</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>
|
||||
Lewa strona
|
||||
</th>
|
||||
<th>
|
||||
Prawa strona
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let flashcard of set.flashcards; let i = index">
|
||||
<td class="puzzle">{{flashcard.left_side}}</td>
|
||||
<td class="puzzle-right">{{flashcard.right_side}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<app-comments [what]="'flashcardsets'"></app-comments>
|
||||
|
||||
</div>
|
||||
|
||||
<p-dialog header="Potwierdź" [(visible)]="display">
|
||||
Czy chcesz usunąć fiszkę?
|
||||
<p-footer>
|
||||
<button type="button" pButton icon="pi pi-check" (click)="deleteSet()" label="TAK"></button>
|
||||
<button type="button" pButton icon="pi pi-close" (click)="display=false" label="NIE" class="ui-button-secondary"></button>
|
||||
</p-footer>
|
||||
</p-dialog>
|
||||
</div>
|
@ -0,0 +1,65 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsSetDetailComponent } from './flashcards-set-detail.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RoutingStateService } from '../../routing-state.service';
|
||||
|
||||
describe('FlashcardsSetDetailComponent', () => {
|
||||
let component: FlashcardsSetDetailComponent;
|
||||
let fixture: ComponentFixture<FlashcardsSetDetailComponent>;
|
||||
let mockSet: any;
|
||||
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsSetDetailComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService, RoutingStateService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsSetDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
mockSet = {
|
||||
name: 'testName',
|
||||
flashcards: [
|
||||
{
|
||||
left_side: 'testLeftSide',
|
||||
right_side: 'testRightSide'
|
||||
}
|
||||
]
|
||||
};
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
// testowanie DOM
|
||||
it('should render set name', () => {
|
||||
component.set = mockSet;
|
||||
fixture.detectChanges();
|
||||
const setName = document.querySelector('h2').innerHTML;
|
||||
expect(setName).toEqual(mockSet.name);
|
||||
});
|
||||
|
||||
it('should render flashcards sides', () => {
|
||||
component.set = mockSet;
|
||||
fixture.detectChanges();
|
||||
const leftSide = document.querySelector('.puzzle').innerHTML;
|
||||
expect(leftSide).toEqual('testLeftSide');
|
||||
const rightSide = document.querySelector('.puzzle-right').innerHTML;
|
||||
expect(rightSide).toEqual('testRightSide');
|
||||
});
|
||||
});
|
@ -0,0 +1,102 @@
|
||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
||||
import { Set } from '../set';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { RoutingStateService } from '../../routing-state.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-set-detail',
|
||||
templateUrl: './flashcards-set-detail.component.html',
|
||||
styleUrls: ['./flashcards-set-detail.component.css']
|
||||
})
|
||||
export class FlashcardsSetDetailComponent implements OnInit, OnDestroy {
|
||||
id: number;
|
||||
set: any;
|
||||
flashcardSubscribtion: Subscription;
|
||||
testTypeMenu = false;
|
||||
user: Boolean = false;
|
||||
ShowStatus: Boolean = false;
|
||||
permission: string;
|
||||
owner;
|
||||
owned: Boolean = false;
|
||||
display = false;
|
||||
|
||||
constructor(private route: ActivatedRoute, private flashcardsService: FlashcardsService, private router: Router,
|
||||
private routingState: RoutingStateService, public snackBar: MatSnackBar) { }
|
||||
ngOnInit() {
|
||||
const previousUrl = this.routingState.getPreviousUrl();
|
||||
if (previousUrl.indexOf('test-gen') === -1) {
|
||||
sessionStorage.setItem('previousUrl', previousUrl);
|
||||
}
|
||||
this.id = this.route.snapshot.params.id;
|
||||
this.flashcardSubscribtion = this.flashcardsService.getSet(this.id).subscribe(data => { this.set = data; });
|
||||
this.IsLogin();
|
||||
this.owner = this.flashcardsService.getOwner();
|
||||
this.isOwner();
|
||||
}
|
||||
|
||||
isOwner() {
|
||||
const currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
if (currentUser.username === this.owner) {
|
||||
this.owned = true;
|
||||
}
|
||||
} else {
|
||||
this.owned = false;
|
||||
}
|
||||
}
|
||||
|
||||
showTestTypeMenu() {
|
||||
this.testTypeMenu = true;
|
||||
}
|
||||
|
||||
IsLogin() {
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
this.user = true;
|
||||
} else {
|
||||
this.user = false;
|
||||
}
|
||||
}
|
||||
|
||||
showPopup() {
|
||||
this.display = true;
|
||||
}
|
||||
|
||||
changePermission(): void {
|
||||
if (this.set.permission === 'Public') {
|
||||
this.permission = 'Private';
|
||||
} else {
|
||||
this.permission = 'Public';
|
||||
}
|
||||
this.flashcardsService.changeSetPermission(this.id, this.permission);
|
||||
this.snackBar.open('Zmieniono pozwolenie na: ' + this.permission, null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-success'] });
|
||||
}
|
||||
|
||||
handleCancelFlashcardsTestyTypeMenu(e) {
|
||||
this.testTypeMenu = e;
|
||||
}
|
||||
|
||||
navigateToEditMode() {
|
||||
this.router.navigate(['flashcards/sets/edit', this.id]);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.flashcardSubscribtion.unsubscribe();
|
||||
}
|
||||
|
||||
deleteSet() {
|
||||
const data = this.id;
|
||||
this.flashcardSubscribtion = this.flashcardsService.deleteSet(data);
|
||||
this.display = false;
|
||||
}
|
||||
|
||||
goBack() {
|
||||
const previousUrl = sessionStorage.getItem('previousUrl');
|
||||
sessionStorage.removeItem('previousUrl');
|
||||
this.router.navigate([previousUrl]);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
.listItem:hover {
|
||||
background-color: rgb(206, 168, 86);
|
||||
}
|
||||
|
||||
.listItem:active{
|
||||
background-color: #4BC7FA;
|
||||
}
|
||||
|
||||
.listItem{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.mobile{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.empty{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content{
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
ag-grid-angular{
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.buttons-container > div{
|
||||
margin: 10px;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<div class="wrapper">
|
||||
<div class="content">
|
||||
<app-flashcards></app-flashcards>
|
||||
<br />
|
||||
<h1>FISZKI</h1>
|
||||
<br />
|
||||
<div class="buttons-container">
|
||||
<div *ngIf="logged">
|
||||
<button class="btn btn-study-cave" (click)="toFlashcardsMaker()"><i class="fas fa-plus"></i> Dodaj fiszki</button>
|
||||
</div>
|
||||
<div *ngIf="logged" class="btn-group btn-group-toggle" data-toggle="buttons">
|
||||
<label class="btn btn-study-cave active" (click)="ShowPublic()">
|
||||
<input type="radio" name="options" id="option1" autocomplete="off" checked><i class="fas fa-globe"></i> Publiczne
|
||||
</label>
|
||||
<label class="btn btn-study-cave" (click)="ShowPrivate()">
|
||||
<input type="radio" name="options" id="option2" autocomplete="off"><i class="fas fa-user-secret"></i> Prywatne
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<ag-grid-angular style="width: 100%; height: 475px;" class="ag-theme-dark" [rowData]="sets" [columnDefs]="columnDefs" [enableSorting]="true"
|
||||
[enableFilter]="true" (gridReady)="onGridReady($event)" (gridSizeChanged)="onGridSizeChanged($event)" [gridOptions]="gridOptions"
|
||||
[pagination]="true" [paginationAutoPageSize]="true" (rowClicked)="onRowClicked($event)" [localeText]="localeText"
|
||||
(gridColumnsChanged)="onGidColumnsChanged($event)">
|
||||
</ag-grid-angular>
|
||||
<p-dialog header="Potwierdź" [(visible)]="display">
|
||||
Czy chcesz usunąć fiszkę?
|
||||
<p-footer>
|
||||
<button type="button" pButton icon="pi pi-check" (click)="deleteSet()" label="TAK"></button>
|
||||
<button type="button" pButton icon="pi pi-close" (click)="display=false" label="NIE" class="ui-button-secondary"></button>
|
||||
</p-footer>
|
||||
</p-dialog>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,35 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsSetsListComponent } from './flashcards-sets-list.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsSetsListComponent', () => {
|
||||
let component: FlashcardsSetsListComponent;
|
||||
let fixture: ComponentFixture<FlashcardsSetsListComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsSetsListComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsSetsListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,271 @@
|
||||
import { Component, OnInit, Output, EventEmitter, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Set } from '../set';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { FilterPipe } from '../../filter.pipe';
|
||||
import { GridOptions, RowDoubleClickedEvent } from 'ag-grid-community/main';
|
||||
import localeText from './localeText';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-sets-list',
|
||||
templateUrl: './flashcards-sets-list.component.html',
|
||||
styleUrls: ['./flashcards-sets-list.component.css']
|
||||
})
|
||||
export class FlashcardsSetsListComponent implements OnInit, OnDestroy {
|
||||
|
||||
sets = [];
|
||||
privatesets = [];
|
||||
setsEmpty = true;
|
||||
selectedSet: Set;
|
||||
flashcardSubscription: Subscription;
|
||||
flashcardSubscriptionOwners: Subscription;
|
||||
user: Boolean;
|
||||
ShowStatus: Boolean = false;
|
||||
owner;
|
||||
searchPublic = 'Public';
|
||||
searchOwner;
|
||||
gridApi;
|
||||
gridColumnApi;
|
||||
public gridOptions: GridOptions;
|
||||
localeText = localeText;
|
||||
logged = false;
|
||||
publicMode = true;
|
||||
permission;
|
||||
display = false;
|
||||
isGroup = false;
|
||||
|
||||
columnDefs = [
|
||||
{ headerName: 'Nazwa', field: 'name', headerTooltip: 'Nazwa' },
|
||||
{ headerName: 'Data dodania', field: 'add_date', headerTooltip: 'Data dodania', hide: false },
|
||||
{ headerName: 'Data modyfikacji', field: 'edit_date', headerTooltip: 'Data modyfikacji', hide: false },
|
||||
{ headerName: 'Właściciel', field: 'owner', headerTooltip: 'Właściciel', hide: false },
|
||||
{ headerName: 'Grupa', field: 'group', headerTooltip: 'Grupa', hide: !this.isGroup },
|
||||
{
|
||||
headerName: '',
|
||||
suppressMenu: true,
|
||||
suppressSorting: true,
|
||||
cellRenderer: this.customCellRendererFunc,
|
||||
hide: !this.isGroup
|
||||
}
|
||||
];
|
||||
setToDelete: any;
|
||||
constructor(private flashcardsService: FlashcardsService, private router: Router, public snackBar: MatSnackBar) { }
|
||||
|
||||
customCellRendererFunc(params) {
|
||||
const currentUser = JSON.parse(localStorage.getItem('currentUser'));
|
||||
if (!currentUser) {
|
||||
return '';
|
||||
} else if (params.data['owner'] === currentUser.username) {
|
||||
return `
|
||||
<button type="button" data-action-type="remove" class="btn btn-study-cave btn-sm" title="Usuń">
|
||||
<i class="fas fa-trash-alt" data-action-type="remove"></i></button>
|
||||
<button type="button" data-action-type="changePermission" class="btn btn-study-cave btn-sm" title="Uprawnienia">
|
||||
<i class="fas fa-unlock" data-action-type="changePermission"></i></button>
|
||||
`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
onSelect(set: Set): void {
|
||||
this.selectedSet = set;
|
||||
this.router.navigate(['flashcards/sets', this.selectedSet.id]);
|
||||
this.flashcardsService.setOwner(this.selectedSet.owner);
|
||||
}
|
||||
|
||||
toFlashcardsMaker() {
|
||||
this.router.navigate(['flashcards/add']);
|
||||
}
|
||||
|
||||
public onRowClicked(e) {
|
||||
if (e.event.target !== undefined) {
|
||||
const data = e.data;
|
||||
const actionType = e.event.target.getAttribute('data-action-type');
|
||||
|
||||
switch (actionType) {
|
||||
case 'remove':
|
||||
return this.onActionRemoveClick(e);
|
||||
case 'changePermission':
|
||||
return this.changePermission(e);
|
||||
default:
|
||||
return this.goToSets(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
public onActionRemoveClick(e) {
|
||||
this.display = true;
|
||||
this.setToDelete = e.data.id;
|
||||
}
|
||||
|
||||
deleteSet() {
|
||||
const data = this.setToDelete;
|
||||
this.flashcardSubscription = this.flashcardsService.deleteSet(data);
|
||||
this.display = false;
|
||||
}
|
||||
|
||||
changePermission(e): void {
|
||||
if (e.data.permission === 'Public') {
|
||||
this.permission = 'Private';
|
||||
} else {
|
||||
this.permission = 'Public';
|
||||
}
|
||||
this.flashcardsService.changeSetPermission(e.data.id, this.permission);
|
||||
this.snackBar.open('Zmieniono pozwolenie na: ' + this.permission, null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-success'] });
|
||||
}
|
||||
|
||||
goToSets(e) {
|
||||
this.router.navigate(['flashcards/sets', e.data.id]);
|
||||
this.flashcardsService.setOwner(e.data.owner);
|
||||
}
|
||||
|
||||
IsLogin() {
|
||||
const own = JSON.parse(localStorage.getItem('currentUser'));
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
this.user = true;
|
||||
this.searchOwner = own.username;
|
||||
} else {
|
||||
this.user = false;
|
||||
this.searchOwner = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
ShowPublic() {
|
||||
this.sets = [];
|
||||
this.ShowStatus = false;
|
||||
this.getSets();
|
||||
}
|
||||
|
||||
ShowPrivate() {
|
||||
this.privatesets = [];
|
||||
this.ShowStatus = true;
|
||||
this.getSetsOwners();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
this.logged = true;
|
||||
}
|
||||
|
||||
this.gridOptions = {
|
||||
rowHeight: 50,
|
||||
headerHeight: 25,
|
||||
getRowStyle: function (params) {
|
||||
return {
|
||||
cursor: 'pointer'
|
||||
};
|
||||
},
|
||||
};
|
||||
this.getSets();
|
||||
this.IsLogin();
|
||||
this.refreshColumns();
|
||||
}
|
||||
|
||||
getSets(): void {
|
||||
this.isGroup = false;
|
||||
this.flashcardSubscription = this.flashcardsService.getSets()
|
||||
.subscribe(data => {
|
||||
this.sets = data;
|
||||
if (this.sets.length > 0) {
|
||||
this.setsEmpty = false;
|
||||
} else {
|
||||
this.setsEmpty = true;
|
||||
}
|
||||
this.refreshColumns();
|
||||
});
|
||||
}
|
||||
|
||||
getSetsOwners(): void {
|
||||
this.isGroup = true;
|
||||
this.flashcardSubscriptionOwners = this.flashcardsService.getSetsOwners()
|
||||
.subscribe(data => {
|
||||
data.forEach((x, i) => {
|
||||
if (!x['group']) {
|
||||
x['group'] = 'Brak';
|
||||
}
|
||||
});
|
||||
this.sets = data;
|
||||
if (this.sets.length > 0) {
|
||||
this.setsEmpty = false;
|
||||
} else {
|
||||
this.setsEmpty = true;
|
||||
}
|
||||
this.refreshColumns();
|
||||
});
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.gridColumnApi = params.columnApi;
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
onGridSizeChanged(params) {
|
||||
if (params.clientWidth < 800) {
|
||||
this.columnDefs = [
|
||||
{ headerName: 'Nazwa', field: 'name', headerTooltip: 'Nazwa' },
|
||||
{ headerName: 'Data dodania', field: 'add_date', headerTooltip: 'Data dodania', hide: true },
|
||||
{ headerName: 'Data modyfikacji', field: 'edit_date', headerTooltip: 'Data modyfikacji', hide: true },
|
||||
{ headerName: 'Właściciel', field: 'owner', headerTooltip: 'Właściciel', hide: true },
|
||||
{ headerName: 'Grupa', field: 'group', headerTooltip: 'Grupa', hide: !this.isGroup },
|
||||
{
|
||||
headerName: '',
|
||||
suppressMenu: true,
|
||||
suppressSorting: true,
|
||||
cellRenderer: this.customCellRendererFunc,
|
||||
hide: !this.isGroup
|
||||
}
|
||||
];
|
||||
} else {
|
||||
this.columnDefs = [
|
||||
{ headerName: 'Nazwa', field: 'name', headerTooltip: 'Nazwa' },
|
||||
{ headerName: 'Data dodania', field: 'add_date', headerTooltip: 'Data dodania', hide: false },
|
||||
{ headerName: 'Data modyfikacji', field: 'edit_date', headerTooltip: 'Data modyfikacji', hide: false },
|
||||
{ headerName: 'Właściciel', field: 'owner', headerTooltip: 'Właściciel', hide: false },
|
||||
{ headerName: 'Grupa', field: 'group', headerTooltip: 'Grupa', hide: !this.isGroup },
|
||||
{
|
||||
headerName: '',
|
||||
suppressMenu: true,
|
||||
suppressSorting: true,
|
||||
cellRenderer: this.customCellRendererFunc,
|
||||
hide: !this.isGroup
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
params.api.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
onGidColumnsChanged(params) {
|
||||
params.api.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.flashcardSubscription) {
|
||||
this.flashcardSubscription.unsubscribe();
|
||||
}
|
||||
if (this.flashcardSubscriptionOwners) {
|
||||
this.flashcardSubscriptionOwners.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
refreshColumns() {
|
||||
this.columnDefs = [
|
||||
{ headerName: 'Nazwa', field: 'name', headerTooltip: 'Nazwa' },
|
||||
{ headerName: 'Data dodania', field: 'add_date', headerTooltip: 'Data dodania', hide: false },
|
||||
{ headerName: 'Data modyfikacji', field: 'edit_date', headerTooltip: 'Data modyfikacji', hide: false },
|
||||
{ headerName: 'Właściciel', field: 'owner', headerTooltip: 'Właściciel', hide: false },
|
||||
{ headerName: 'Grupa', field: 'group', headerTooltip: 'Grupa', hide: !this.isGroup },
|
||||
{
|
||||
headerName: '',
|
||||
suppressMenu: true,
|
||||
suppressSorting: true,
|
||||
cellRenderer: this.customCellRendererFunc,
|
||||
hide: !this.isGroup
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
90
src/app/flashcards/flashcards-sets-list/localeText.ts
Normal file
90
src/app/flashcards/flashcards-sets-list/localeText.ts
Normal file
@ -0,0 +1,90 @@
|
||||
const localeText = {
|
||||
|
||||
// for filter panel
|
||||
page: 'Strona',
|
||||
more: 'Więcej',
|
||||
to: 'do',
|
||||
of: 'z',
|
||||
next: '>',
|
||||
last: '>>',
|
||||
first: '<<',
|
||||
previous: '<',
|
||||
loadingOoo: 'Ładowanie...',
|
||||
|
||||
// for set filter
|
||||
selectAll: 'Wybierz wszystkie',
|
||||
searchOoo: 'Szukaj',
|
||||
blanks: 'Luki',
|
||||
|
||||
// for number filter and text filter
|
||||
filterOoo: 'Filtruj...',
|
||||
applyFilter: 'Zastosuj filtr',
|
||||
|
||||
// for number filter
|
||||
equals: 'Równy',
|
||||
notEqual: 'Nie równy',
|
||||
lessThan: 'Mniejszy niż',
|
||||
greaterThan: 'Większy niż',
|
||||
|
||||
// for text filter
|
||||
contains: 'Zawiera',
|
||||
notContains: 'Nie zawiera',
|
||||
startsWith: 'Zaczyna się od',
|
||||
endsWith: 'Kończy się na',
|
||||
|
||||
// the header of the default group column
|
||||
group: 'Grupa',
|
||||
|
||||
// tool panel
|
||||
columns: 'Kolumny',
|
||||
rowGroupColumns: 'Grupa wiersza kolumn',
|
||||
rowGroupColumnsEmptyMessage: 'Przeciągnij kolumny do grupy',
|
||||
valueColumns: 'Wartości kolumn',
|
||||
pivotMode: 'Pivot-Mode',
|
||||
groups: 'Grupy',
|
||||
values: 'Wartości',
|
||||
pivots: 'Pivots',
|
||||
valueColumnsEmptyMessage: 'Przeciągnij kolumny do agregacji',
|
||||
pivotColumnsEmptyMessage: 'Przeciągnij kolumny na oś',
|
||||
toolPanelButton: 'Narzędzia',
|
||||
|
||||
// other
|
||||
noRowsToShow: 'Brak fiszek do wyświetlenia',
|
||||
|
||||
// enterprise menu
|
||||
pinColumn: 'Przypiąta kolumna',
|
||||
valueAggregation: 'Sumuj',
|
||||
autosizeThiscolumn: 'Autosize this column',
|
||||
autosizeAllColumns: 'Autosize All Columns',
|
||||
groupBy: 'Grupuj po',
|
||||
ungroupBy: 'Nie grupuj po',
|
||||
resetColumns: 'Resetuj kolumny',
|
||||
expandAll: 'Rozszerz wszystko',
|
||||
collapseAll: 'Zwiń wszystko',
|
||||
toolPanel: 'Narzędzia',
|
||||
export: 'Export',
|
||||
csvExport: 'CSV Export',
|
||||
excelExport: 'Excel Export',
|
||||
|
||||
// enterprise menu pinning
|
||||
pinLeft: 'Przypnij <<',
|
||||
pinRight: 'Przypnij >>',
|
||||
noPin: 'Nie przypinaj <>',
|
||||
|
||||
// enterprise menu aggregation and status panel
|
||||
sum: 'Suma',
|
||||
min: 'Minimum',
|
||||
max: 'Maksimum',
|
||||
none: 'Nic',
|
||||
count: 'Ilość',
|
||||
average: 'Średnia',
|
||||
|
||||
// standard menu
|
||||
copy: 'Kopiuj',
|
||||
copyWithHeaders: 'Kopiuj z nagłówkami',
|
||||
ctrlC: 'ctrl + C',
|
||||
paste: 'wklej',
|
||||
ctrlV: 'ctrl + C'
|
||||
};
|
||||
|
||||
export default localeText;
|
@ -0,0 +1,4 @@
|
||||
div{
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<div>
|
||||
<button class="btn btn-study-cave" (click)="goToTestGenFill()">Uzupełnij</button>
|
||||
<button class="btn btn-study-cave" (click)="goToTestGen()">Pary</button>
|
||||
<button class="btn btn-study-cave" (click)="goToTestGenTyperace()">Na czas</button>
|
||||
<button class="btn btn-study-cave" (click)="goToTestGenMemory()">Memory</button>
|
||||
<button class="btn btn-study-cave" (click)="cancelMenu()"><i class="fas fa-times"></i> Anuluj</button>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsTestTypeMenuComponent } from './flashcards-test-type-menu.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsTestTypeMenuComponent', () => {
|
||||
let component: FlashcardsTestTypeMenuComponent;
|
||||
let fixture: ComponentFixture<FlashcardsTestTypeMenuComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsTestTypeMenuComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsTestTypeMenuComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,37 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-test-type-menu',
|
||||
templateUrl: './flashcards-test-type-menu.component.html',
|
||||
styleUrls: ['./flashcards-test-type-menu.component.css']
|
||||
})
|
||||
export class FlashcardsTestTypeMenuComponent implements OnInit {
|
||||
@Input() id: Number;
|
||||
@Output() cancel = new EventEmitter;
|
||||
|
||||
cancelMenu() {
|
||||
this.cancel.emit(false);
|
||||
}
|
||||
|
||||
goToTestGen() {
|
||||
this.router.navigate(['flashcards/test-gen/flashcards-pairs', this.id]);
|
||||
}
|
||||
|
||||
goToTestGenFill() {
|
||||
this.router.navigate(['flashcards/test-gen/flashcards-filling-in', this.id]);
|
||||
}
|
||||
|
||||
goToTestGenMemory() {
|
||||
this.router.navigate(['flashcards/test-gen/flashcards-memory', this.id]);
|
||||
}
|
||||
goToTestGenTyperace() {
|
||||
this.router.navigate(['flashcards/test-gen/flashcards-typerace', this.id]);
|
||||
}
|
||||
|
||||
constructor(private router: Router) { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
#container-small {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 32%;
|
||||
min-height: 400px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#container-large {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
width: 62%;
|
||||
min-height: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.content {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#container-small {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
#container-small, #container-large {
|
||||
width: 90%;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
<div class="content">
|
||||
<div id="container-small">
|
||||
<h4>Przepisywanie fiszek na czas</h4>
|
||||
<br />
|
||||
<div>
|
||||
<b>Nazwa zestawu: </b>
|
||||
<i>{{ name }}</i>
|
||||
<br />
|
||||
<b>Kategoria: </b>
|
||||
<i>{{ category }}</i>
|
||||
</div>
|
||||
<div *ngIf="started">
|
||||
<div>
|
||||
<div>
|
||||
<b>Uzupełniono: </b>
|
||||
<span> {{ filled }} z {{ length_test }} fiszek</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Poprawnych odpowiedzi: </b>
|
||||
<span> {{ good }} na {{ length_test }}</span><br />
|
||||
<b>Złych odpowiedzi: </b>
|
||||
<span> {{ bad }} na {{ length_test }}</span><br />
|
||||
<div *ngIf="this.filled < this.length_test && !finish">
|
||||
<b>Twój czas: </b>
|
||||
<span> {{minute}} m {{second}} s {{millisecond}} ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-large">
|
||||
<div *ngIf="started">
|
||||
<div *ngIf="this.filled >= 1 && !finish">
|
||||
Poprzednia odpowiedź:<br />
|
||||
{{flashcards[index-1].content}} {{stoptimes[index-1].m}} m {{stoptimes[index-1].s}} s {{stoptimes[index-1].ms}} ms
|
||||
</div>
|
||||
<div *ngIf="this.filled < this.length_test && !finish">
|
||||
Podaj odpowiedź:<br />
|
||||
{{flashcards[index].content}}
|
||||
<input appAutofocus [(ngModel)]="answer" class="mr-2" placeholder="odpowiedź" (keyup.enter)="verifyAnswer()" >
|
||||
<button class="btn btn-study-cave" (click)="verifyAnswer()" ><i class="fas fa-check-circle"></i> Sprawdź</button>
|
||||
</div>
|
||||
<div *ngIf="this.is_correct === true && !finish">ODPOWIEDŹ POPRAWNA</div>
|
||||
<div *ngIf="this.is_correct === false && !finish">ODPOWIEDŹ NIEPOPRAWNA</div>
|
||||
<div *ngIf="this.filled < this.length_test-1 && !finish">
|
||||
Następne pytanie:<br />
|
||||
{{flashcards[index+1].content}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="finish">
|
||||
<app-test-results [result]="good" [maxPts]="length_test" [minutes]="finalminute" [seconds]="finalsecond" [milliseconds]="finalmillisecond" [timer]="true"></app-test-results>
|
||||
</div>
|
||||
<div *ngIf="!finish">
|
||||
<button class="btn btn-study-cave" *ngIf="!started" (click)="start()"><i class="far fa-play-circle"></i> Rozpocznij test</button>
|
||||
</div>
|
||||
<button class="btn btn-study-cave" *ngIf="finish" routerLink="/flashcards/sets/{{ id }}"><i class="far fa-stop-circle"></i> Zakończ test</button>
|
||||
<button class="btn btn-study-cave" *ngIf="started && !finish && !not_last"(click)="finished()"><i class="far fa-stop-circle"></i> Przejdź do wyniku</button>
|
||||
<br />
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets/{{ id }}"><i class="fas fa-arrow-left"></i> Wróć do zestawu</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,34 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsTyperaceTestComponent } from './flashcards-typerace-test.component';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('FlashcardsTyperaceTestComponent', () => {
|
||||
let component: FlashcardsTyperaceTestComponent;
|
||||
let fixture: ComponentFixture<FlashcardsTyperaceTestComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsTyperaceTestComponent ],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsTyperaceTestComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,167 @@
|
||||
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
|
||||
import { FlashcardsService } from '../flashcards.service';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards-typerace-test',
|
||||
templateUrl: './flashcards-typerace-test.component.html',
|
||||
styleUrls: ['./flashcards-typerace-test.component.css']
|
||||
})
|
||||
export class FlashcardsTyperaceTestComponent implements OnInit, OnDestroy {
|
||||
|
||||
id: number;
|
||||
private flashcardSubscribtionMeta: Subscription;
|
||||
private flashcardSubscribtion: Subscription;
|
||||
private flashcardSubscribtionCheck: Subscription;
|
||||
|
||||
name: String;
|
||||
category: String;
|
||||
length_test: number;
|
||||
goodNow: number;
|
||||
started: Boolean = false;
|
||||
finish: Boolean = false;
|
||||
flashcards: Array<Object> = [];
|
||||
filled = 0;
|
||||
good = 0;
|
||||
bad = 0;
|
||||
answer: String;
|
||||
index = 0;
|
||||
not_last: Boolean = true;
|
||||
is_correct: Boolean;
|
||||
allAnswers = [];
|
||||
stoptimes = [];
|
||||
|
||||
hour= 0;
|
||||
minute= 0;
|
||||
second= 0;
|
||||
millisecond= 0;
|
||||
starttime= false;
|
||||
pause= false;
|
||||
x= 10;
|
||||
intervalId;
|
||||
|
||||
finalhour= 0;
|
||||
finalminute= 0;
|
||||
finalsecond= 0;
|
||||
finalmillisecond= 0;
|
||||
|
||||
constructor(private flashcardsService: FlashcardsService, private route: ActivatedRoute) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.id = this.route.snapshot.params.id;
|
||||
this.flashcardSubscribtionMeta = this.flashcardsService.getSet(this.id).subscribe(data => {
|
||||
this.name = data['name'];
|
||||
this.category = data['category'];
|
||||
});
|
||||
this.flashcardSubscribtion = this.flashcardsService.getTestFilling(this.id).subscribe(data => {
|
||||
this.length_test = data.length;
|
||||
this.flashcards = data;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
start() {
|
||||
this.started = true;
|
||||
this.onStart();
|
||||
}
|
||||
finished() {
|
||||
this.finish = true;
|
||||
this.onPause();
|
||||
}
|
||||
verifyAnswer() {
|
||||
this.reset();
|
||||
const body = [];
|
||||
const n = this.length_test;
|
||||
if (this.answer === '') {
|
||||
this.answer = ' ';
|
||||
}
|
||||
this.allAnswers.push({
|
||||
id: this.index,
|
||||
answer: this.answer,
|
||||
});
|
||||
body.push({
|
||||
id: this.flashcards[this.index]['id'],
|
||||
content: this.answer,
|
||||
side: this.flashcards[this.index]['side'],
|
||||
});
|
||||
this.flashcardSubscribtionCheck = this.flashcardsService.testCheck(this.id, body[0])
|
||||
.subscribe(data => {
|
||||
this.is_correct = data.result;
|
||||
if (this.is_correct === true) {
|
||||
this.good = this.good + 1;
|
||||
} else {
|
||||
this.bad = this.bad + 1;
|
||||
}
|
||||
});
|
||||
if (this.index < this.length_test) {
|
||||
this.index = this.index + 1;
|
||||
this.filled = this.filled + 1;
|
||||
this.answer = '';
|
||||
}
|
||||
if (this.index === this.length_test) {
|
||||
this.not_last = false;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.finalhour = this.finalhour + this.hour;
|
||||
this.finalminute = this.finalminute + this.minute;
|
||||
this.finalsecond = this.finalsecond + this.second;
|
||||
this.finalmillisecond = this.finalmillisecond + this.millisecond;
|
||||
this.stoptimes.push({
|
||||
id: this.index,
|
||||
m: this.minute,
|
||||
s: this.second,
|
||||
ms: this.millisecond,
|
||||
});
|
||||
|
||||
this.x = 0;
|
||||
this.hour = this.minute = this.second = this.millisecond = 0;
|
||||
this.starttime = false;
|
||||
this.pause = false;
|
||||
clearInterval(this.intervalId);
|
||||
this.onStart();
|
||||
}
|
||||
|
||||
onStart() {
|
||||
this.x = 10;
|
||||
this.starttime = true;
|
||||
this.intervalId = setInterval(() => {
|
||||
this.updateTime();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
onPause() {
|
||||
this.pause = true;
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
|
||||
updateTime() {
|
||||
this.millisecond += this.x;
|
||||
|
||||
if (this.millisecond > 90) {
|
||||
this.millisecond = 0;
|
||||
this.second++;
|
||||
}
|
||||
|
||||
if (this.second > 59) {
|
||||
this.second = 0;
|
||||
this.minute++;
|
||||
}
|
||||
|
||||
if (this.minute > 59) {
|
||||
this.minute = 0;
|
||||
this.hour++;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.flashcardSubscribtionMeta.unsubscribe();
|
||||
this.flashcardSubscribtion.unsubscribe();
|
||||
if (this.flashcardSubscribtionCheck) {
|
||||
this.flashcardSubscribtionCheck.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
66
src/app/flashcards/flashcards.module.ts
Normal file
66
src/app/flashcards/flashcards.module.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import * as $ from 'jquery';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { FlashcardsComponent } from './flashcards/flashcards.component';
|
||||
import { FlashcardsSetsListComponent } from './flashcards-sets-list/flashcards-sets-list.component';
|
||||
import { FlashcardsService } from './flashcards.service';
|
||||
import { FlashcardsAddComponent } from './flashcards-add/flashcards-add.component';
|
||||
import { FlashcardsAddTableComponent } from './flashcards-add-table/flashcards-add-table.component';
|
||||
import { FlashcardsAddCsvComponent } from './flashcards-add-csv/flashcards-add-csv.component';
|
||||
import { FlashcardsSetDetailComponent } from './flashcards-set-detail/flashcards-set-detail.component';
|
||||
import { FlashcardsEditTableComponent } from './flashcards-edit-table/flashcards-edit-table.component';
|
||||
import { FlashcardsPairsTestComponent } from './flashcards-pairs-test/flashcards-pairs-test.component';
|
||||
import { FlashcardsPairsTestSetComponent } from './flashcards-pairs-test-set/flashcards-pairs-test-set.component';
|
||||
import { FlashcardsTestTypeMenuComponent } from './flashcards-test-type-menu/flashcards-test-type-menu.component';
|
||||
import { FlashcardsFillingInTestComponent } from './flashcards-filling-in-test/flashcards-filling-in-test.component';
|
||||
import { FlashcardsMemoryTestComponent } from './flashcards-memory-test/flashcards-memory-test.component';
|
||||
import { FlashcardsMemoryTestSetComponent } from './flashcards-memory-test-set/flashcards-memory-test-set.component';
|
||||
import { FlashcardsTyperaceTestComponent } from './flashcards-typerace-test/flashcards-typerace-test.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TestResultsComponent } from './test-results/test-results.component';
|
||||
import { FilterUserPipe } from '../filter-user.pipe';
|
||||
import { FilterPipe } from '../filter.pipe';
|
||||
import { AgGridModule } from 'ag-grid-angular';
|
||||
import { DialogModule } from 'primeng/dialog';
|
||||
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule,
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule,
|
||||
HttpClientModule,
|
||||
AgGridModule.withComponents([]),
|
||||
DialogModule,
|
||||
ConfirmDialogModule,
|
||||
SharedModule
|
||||
|
||||
],
|
||||
declarations: [
|
||||
TestResultsComponent,
|
||||
FlashcardsComponent,
|
||||
FlashcardsSetsListComponent,
|
||||
FlashcardsAddComponent,
|
||||
FlashcardsAddTableComponent,
|
||||
FlashcardsAddCsvComponent,
|
||||
FlashcardsSetDetailComponent,
|
||||
FlashcardsEditTableComponent,
|
||||
FlashcardsPairsTestComponent,
|
||||
FlashcardsPairsTestSetComponent,
|
||||
FlashcardsTestTypeMenuComponent,
|
||||
FlashcardsFillingInTestComponent,
|
||||
FlashcardsMemoryTestComponent,
|
||||
FlashcardsMemoryTestSetComponent,
|
||||
FlashcardsTyperaceTestComponent,
|
||||
FilterUserPipe,
|
||||
FilterPipe
|
||||
],
|
||||
providers: [FlashcardsService, FilterPipe, FilterUserPipe],
|
||||
})
|
||||
export class FlashcardsModule { }
|
23
src/app/flashcards/flashcards.service.spec.ts
Normal file
23
src/app/flashcards/flashcards.service.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsService } from './flashcards.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { AuthenticationService } from '../authentication.service';
|
||||
|
||||
describe('FlashcardsService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [FlashcardsService, AuthenticationService],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
imports: [ RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([FlashcardsService], (service: FlashcardsService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
160
src/app/flashcards/flashcards.service.ts
Normal file
160
src/app/flashcards/flashcards.service.ts
Normal file
@ -0,0 +1,160 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpRequest, HttpEvent } from '@angular/common/http';
|
||||
import { Http, Response, Headers, RequestOptions } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { of } from 'rxjs/observable/of';
|
||||
import { Set } from './set';
|
||||
import 'rxjs/add/operator/map';
|
||||
import { Router } from '@angular/router';
|
||||
import { AuthenticationService } from '../authentication.service';
|
||||
import { THIS_EXPR } from '@angular/compiler/src/output/output_ast';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Injectable()
|
||||
export class FlashcardsService {
|
||||
|
||||
// tslint:disable-next-line:max-line-length
|
||||
constructor(private httpClient: HttpClient, private router: Router, private authenticationService: AuthenticationService,
|
||||
public snackBar: MatSnackBar) { this.setHeaders(); }
|
||||
private headers;
|
||||
owner;
|
||||
|
||||
setHeaders() {
|
||||
if (localStorage.getItem('currentUser')) {
|
||||
this.headers = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': '' + this.authenticationService.getToken()
|
||||
});
|
||||
} else {
|
||||
this.headers = new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
changeSetPermission(id, permission) {
|
||||
this.setHeaders();
|
||||
this.httpClient.put('sets/' + id + '/permission', permission, { headers: this.headers })
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
add(body) {
|
||||
const url = 'sets/';
|
||||
this.sendData(url, body);
|
||||
}
|
||||
|
||||
edit(body) {
|
||||
const url = 'sets/';
|
||||
this.putData(url, body);
|
||||
}
|
||||
|
||||
getSets(): Observable<any> {
|
||||
this.setHeaders();
|
||||
return this.httpClient.get('sets', { headers: this.headers, params: { permission: 'Public' } });
|
||||
}
|
||||
getSetsOwners(): Observable<any> {
|
||||
this.setHeaders();
|
||||
const owner = JSON.parse(localStorage.getItem('currentUser'));
|
||||
return this.httpClient.get('sets', { headers: this.headers, params: { owner: owner.username } });
|
||||
}
|
||||
|
||||
setOwner(owner) {
|
||||
if (owner === null) {
|
||||
this.owner = ' ';
|
||||
} else {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
sendData(url, body) {
|
||||
this.setHeaders();
|
||||
this.httpClient.post(url, body, { headers: this.headers, observe: 'response' })
|
||||
.subscribe(data => { this.sendResponse(data); },
|
||||
error => {
|
||||
this.snackBar.open('Coś poszło nie tak. Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
putData(url, body) {
|
||||
this.setHeaders();
|
||||
this.httpClient.put(url, body, { headers: this.headers, observe: 'response' })
|
||||
.subscribe(data => { this.sendResponse(data); },
|
||||
error => {
|
||||
this.snackBar.open('Coś poszło nie tak. Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
sendResponse(data) {
|
||||
if (data.status === 200) {
|
||||
this.snackBar.open('Operacja przebiegła pomyślnie!', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-success'] });
|
||||
this.router.navigate(['flashcards/sets']);
|
||||
} else {
|
||||
this.snackBar.open('Coś poszło nie tak. Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
}
|
||||
}
|
||||
|
||||
// sending file - import flashcards from CSV
|
||||
pushFileToStorage(file: File, user: string, permission: string, url: string): Observable<HttpEvent<{}>> {
|
||||
const formdata: FormData = new FormData();
|
||||
formdata.append('file', file);
|
||||
formdata.append('owner', user);
|
||||
formdata.append('permission', permission);
|
||||
const req = new HttpRequest('POST', url, formdata, {
|
||||
reportProgress: true,
|
||||
responseType: 'text'
|
||||
});
|
||||
return this.httpClient.request(req);
|
||||
}
|
||||
|
||||
getSet(id) {
|
||||
return this.httpClient.get('sets/' + id + '/');
|
||||
}
|
||||
|
||||
getTestPairing(id) {
|
||||
return this.httpClient.get('sets/' + id + '/test/pairing/');
|
||||
}
|
||||
|
||||
getTestFilling(id) {
|
||||
return this.httpClient.get('sets/' + id + '/test/filling-in/').map((data: Array<Object>) => data);
|
||||
}
|
||||
|
||||
getTestMemory(id) {
|
||||
return this.httpClient.get('sets/' + id + '/test/memory/').map((data: Array<Object>) => data);
|
||||
}
|
||||
|
||||
deleteSet(id) {
|
||||
this.setHeaders();
|
||||
return this.httpClient.delete('sets/' + id, { headers: this.headers, observe: 'response' })
|
||||
.subscribe(data => { this.sendResponse(data); },
|
||||
error => {
|
||||
this.snackBar.open('Coś poszło nie tak. Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// sprawdzanie testu - zapytanie dla jednej fiszki
|
||||
testCheck(id, body) {
|
||||
// id - id zestawu fiszek
|
||||
// ciało body = {id - idFiszki, content - wpisana odpowiedź, side - strona fiszki, którą widział użytkownik}
|
||||
this.setHeaders();
|
||||
return this.httpClient.get(`sets/${id}/${body['id']}/${body['content']}/${body['side']}/test/check/`, { headers: this.headers })
|
||||
.map((data: any) => data);
|
||||
}
|
||||
|
||||
testMemory(id, body) {
|
||||
this.setHeaders();
|
||||
return this.httpClient.get(`sets/${id}/test/memory/check?x=${body['x']}&y=${body['y']}`, { headers: this.headers })
|
||||
.map((data: any) => data);
|
||||
}
|
||||
}
|
3
src/app/flashcards/flashcards/flashcards.component.css
Normal file
3
src/app/flashcards/flashcards/flashcards.component.css
Normal file
@ -0,0 +1,3 @@
|
||||
.btn{
|
||||
margin-bottom: 5px;
|
||||
}
|
4
src/app/flashcards/flashcards/flashcards.component.html
Normal file
4
src/app/flashcards/flashcards/flashcards.component.html
Normal file
@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<button class="btn btn-study-cave" routerLink="/flashcards/sets"><i class="fas fa-scroll"></i> FISZKI</button>
|
||||
<button class="btn btn-study-cave" routerLink="/materials/list"><i class="fas fa-book-open"></i> MATERIAŁY</button>
|
||||
</div>
|
25
src/app/flashcards/flashcards/flashcards.component.spec.ts
Normal file
25
src/app/flashcards/flashcards/flashcards.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FlashcardsComponent } from './flashcards.component';
|
||||
|
||||
describe('FlashcardsComponent', () => {
|
||||
let component: FlashcardsComponent;
|
||||
let fixture: ComponentFixture<FlashcardsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FlashcardsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FlashcardsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
15
src/app/flashcards/flashcards/flashcards.component.ts
Normal file
15
src/app/flashcards/flashcards/flashcards.component.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-flashcards',
|
||||
templateUrl: './flashcards.component.html',
|
||||
styleUrls: ['./flashcards.component.css']
|
||||
})
|
||||
export class FlashcardsComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
10
src/app/flashcards/set.ts
Normal file
10
src/app/flashcards/set.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export interface Set {
|
||||
id: number;
|
||||
name: string;
|
||||
category: string;
|
||||
owner: string;
|
||||
add_date: string;
|
||||
edit_date: string;
|
||||
grade: number;
|
||||
permission: string;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<h2>Twój wynik to {{(result/maxPts*100) | number : '1.0-2' }}%!</h2>
|
||||
<h3>Poprawne odpowiedzi: {{result}}</h3>
|
||||
<h3>Niepoprawne odpowiedzi: {{maxPts-result}}</h3>
|
||||
<div *ngIf="timer">
|
||||
<h3>Twój czas: {{minutes}} m {{seconds}} s {{milliseconds}} ms</h3>
|
||||
</div>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TestResultsComponent } from './test-results.component';
|
||||
|
||||
describe('TestResultsComponent', () => {
|
||||
let component: TestResultsComponent;
|
||||
let fixture: ComponentFixture<TestResultsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ TestResultsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TestResultsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
20
src/app/flashcards/test-results/test-results.component.ts
Normal file
20
src/app/flashcards/test-results/test-results.component.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'app-test-results',
|
||||
templateUrl: './test-results.component.html',
|
||||
styleUrls: ['./test-results.component.css']
|
||||
})
|
||||
export class TestResultsComponent implements OnInit {
|
||||
@Input() result: number;
|
||||
@Input() maxPts: number;
|
||||
@Input() minutes: number;
|
||||
@Input() seconds: number;
|
||||
@Input() milliseconds: number;
|
||||
@Input() timer: Boolean;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
10
src/app/footer/footer.component.css
Normal file
10
src/app/footer/footer.component.css
Normal file
@ -0,0 +1,10 @@
|
||||
.footer{
|
||||
color: white;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
background-color: rgb(24, 22, 22);
|
||||
padding: 1rem 0;
|
||||
}
|
3
src/app/footer/footer.component.html
Normal file
3
src/app/footer/footer.component.html
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="footer">
|
||||
Regulamin | Polityka Cookies | © 2018 StudyCave
|
||||
</div>
|
25
src/app/footer/footer.component.spec.ts
Normal file
25
src/app/footer/footer.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
describe('FooterComponent', () => {
|
||||
let component: FooterComponent;
|
||||
let fixture: ComponentFixture<FooterComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FooterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FooterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
15
src/app/footer/footer.component.ts
Normal file
15
src/app/footer/footer.component.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer',
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrls: ['./footer.component.css']
|
||||
})
|
||||
export class FooterComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
40
src/app/groups/group-creator/group-creator.component.css
Normal file
40
src/app/groups/group-creator/group-creator.component.css
Normal file
@ -0,0 +1,40 @@
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper-add {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
min-height: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: #181616;
|
||||
padding: 30px;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.buttons-container > div {
|
||||
margin: 10px;
|
||||
}
|
35
src/app/groups/group-creator/group-creator.component.html
Normal file
35
src/app/groups/group-creator/group-creator.component.html
Normal file
@ -0,0 +1,35 @@
|
||||
<div class="wrapper">
|
||||
<div class="wrapper-add">
|
||||
<div class="container">
|
||||
<h1>Tworzenie grupy</h1>
|
||||
<br />
|
||||
<form ngNativeValidate action="/" method="post" #user="ngForm" (ngSubmit)="add(user.value)">
|
||||
<label>
|
||||
Wprowadź nazwę dla grupy:
|
||||
<input type="text" name="name" maxlength="150" class="form-control" ngModel required />
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
Wprowadź opis grupy:
|
||||
<textarea name="description" class="form-control" ngModel required></textarea>
|
||||
</label>
|
||||
<br /><br />
|
||||
<button #btn class="btn btn-study-cave" type="submit"><i class="fas fa-check-circle"></i> Dodaj grupę!</button>
|
||||
<button class="btn btn-study-cave" routerLink="/my-groups"><i class="fas fa-arrow-left"></i> Powrót</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p-dialog header="Informacja" [(visible)]="showInfoDialog" [responsive]="true"
|
||||
[minWidth]="300" [minY]="70" [draggable]="false" [closable]="false">
|
||||
<p>Twoja grupa została utworzona prawidłowo.</p>
|
||||
<p>Poniżej znajduje się kod dostępu poprzez który możesz dodawać członków:</p>
|
||||
<!--<p><b>{{ createdGroup.key }}</b></p>-->
|
||||
<p><b>{{ createdGroup.groupKey }}</b></p>
|
||||
<br />
|
||||
<p>Kod ten będzie dostępny także w sekcji "Zarządzaj grupą."</p>
|
||||
<br />
|
||||
<!-- To check later -->
|
||||
<button class="btn btn-study-cave" (click)="showInfoDialog = false" [routerLink]="['/groups/manage', createdGroup.id]">Rozumiem</button>
|
||||
</p-dialog>
|
49
src/app/groups/group-creator/group-creator.component.spec.ts
Normal file
49
src/app/groups/group-creator/group-creator.component.spec.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GroupCreatorComponent } from './group-creator.component';
|
||||
import { GroupsService } from '../groups.service';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { AuthenticationService } from '../../authentication.service';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('GroupCreatorComponent', () => {
|
||||
let component: GroupCreatorComponent;
|
||||
let fixture: ComponentFixture<GroupCreatorComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [GroupCreatorComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [GroupsService, AuthenticationService],
|
||||
imports: [RouterTestingModule, FormsModule, HttpClientModule, MatSnackBarModule, NoopAnimationsModule]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(GroupCreatorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create group', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.autoDetectChanges();
|
||||
spyOn(component, 'add').and.callThrough();
|
||||
fixture.debugElement.nativeElement.querySelectorAll('.form-control')[0].value = 'group-name';
|
||||
fixture.debugElement.nativeElement.querySelectorAll('.form-control')[1].value = 'group-descripion';
|
||||
fixture.debugElement.nativeElement.querySelectorAll('.btn-study-cave')[0].click();
|
||||
expect(component.add).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
}));
|
||||
|
||||
});
|
63
src/app/groups/group-creator/group-creator.component.ts
Normal file
63
src/app/groups/group-creator/group-creator.component.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { Component, OnInit, OnDestroy, ElementRef, ViewChild } from '@angular/core';
|
||||
import { ISubscription } from 'rxjs/Subscription';
|
||||
import { Router } from '@angular/router';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
import { GroupsService } from '../groups.service';
|
||||
import { Group } from '../group';
|
||||
|
||||
@Component({
|
||||
selector: 'app-group-creator',
|
||||
templateUrl: './group-creator.component.html',
|
||||
styleUrls: ['./group-creator.component.css']
|
||||
})
|
||||
export class GroupCreatorComponent implements OnInit, OnDestroy {
|
||||
|
||||
public currentUser: string;
|
||||
public postGroupsSubscription: ISubscription;
|
||||
public createdGroup: Group = {};
|
||||
public showInfoDialog: boolean;
|
||||
|
||||
@ViewChild('btn') btn: ElementRef;
|
||||
|
||||
constructor(private groupsService: GroupsService, private router: Router,
|
||||
private snackBar: MatSnackBar) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.showInfoDialog = false;
|
||||
if (localStorage.getItem('currentUser') !== null) {
|
||||
this.currentUser = JSON.parse(localStorage.getItem('currentUser')).username;
|
||||
}
|
||||
}
|
||||
|
||||
add(value: any) {
|
||||
this.btn.nativeElement.disabled = true;
|
||||
const toSend = {
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
owner: this.currentUser
|
||||
};
|
||||
this.postGroupsSubscription = this.groupsService.postGroup(toSend).subscribe(
|
||||
success => {
|
||||
this.createdGroup = success;
|
||||
this.showInfoDialog = true;
|
||||
},
|
||||
error => {
|
||||
this.btn.nativeElement.disabled = false;
|
||||
this.snackBar.open('Wystąpił błąd serwera. Spróbuj ponownie później.', null,
|
||||
{ duration: 3000, verticalPosition: 'top', panelClass: ['snackbar-error'] });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
goToManageGroup() {
|
||||
this.router.navigate(['groups/manage', this.createdGroup.id]);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.postGroupsSubscription) {
|
||||
this.postGroupsSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user