feat: add feedback module

This commit is contained in:
Jovan Krunić
2021-10-21 06:47:40 +00:00
parent 18ab8d592e
commit 867f9e9b83
13 changed files with 509 additions and 80 deletions

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2021 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Component} from '@angular/core';
import {
SCFeedbackRequest,
SCFeedbackRequestMetaData,
SCMessage,
SCPersonWithoutReferences,
SCThingOriginType,
SCThingType,
} from '@openstapps/core';
import {DataProvider} from '../data/data.provider';
import {DebugDataCollectorService} from '../data/debug-data-collector.service';
import {AlertController, ToastController} from '@ionic/angular';
import {TranslateService} from '@ngx-translate/core';
@Component({
templateUrl: './feedback-page.html',
styleUrls: ['./feedback-page.scss'],
})
export class FeedbackPageComponent {
constructor(
private readonly dataProvider: DataProvider,
private readonly debugDataCollector: DebugDataCollectorService,
private readonly toastController: ToastController,
private readonly alertController: AlertController,
private readonly translateService: TranslateService,
) {}
/**
* Sender of the feedback message
*/
author: SCPersonWithoutReferences = {
uid: '0f53f16a-e618-5ae0-a1b6-336e34f0d4d1',
name: '',
type: SCThingType.Person,
};
/**
* The message to be sent
*/
message: SCMessage = {
uid: '0f53f16a-e618-5ae0-a1b6-336e34f0d4d1',
name: 'Bug',
type: SCThingType.Message,
audiences: [],
categories: [],
origin: {
type: SCThingOriginType.User,
created: new Date().toISOString(),
},
messageBody: '',
};
/**
* Terms of feedback accepted or not
*/
termsAgree = false;
/**
* Show meta data or not
*/
showMetaData = false;
/**
* Feedback successfully sent
*/
submitSuccess = false;
/**
* Terms of feedback accepted or not
*/
metaData: SCFeedbackRequestMetaData;
async ionViewDidEnter() {
this.metaData = await this.debugDataCollector.getFeedbackMetaData();
}
/**
* Assemble and send the feedback
*/
async onSubmit() {
if (this.author.name !== '') {
this.message.authors = [this.author];
}
const feedbackRequest: SCFeedbackRequest = {
...this.message,
metaData: this.metaData,
};
try {
await this.dataProvider.sendFeedback(feedbackRequest);
void this.onSuccess();
} catch {
void this.onError();
}
}
/**
* Show/hide the meta data
*/
toggleShowMetaData() {
this.showMetaData = !this.showMetaData;
}
async onSuccess() {
this.submitSuccess = true;
const toast = await this.toastController.create({
message: this.translateService.instant(
'feedback.system_messages.success',
),
duration: 2000,
});
await toast.present();
}
async onError() {
const alert: HTMLIonAlertElement = await this.alertController.create({
buttons: [this.translateService.instant('app.ui.CLOSE')],
header: this.translateService.instant('app.ui.ERROR'),
message: this.translateService.instant('app.errors.UNKNOWN'),
});
await alert.present();
}
}

View File

@@ -0,0 +1,100 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>{{ 'feedback.page.TITLE' | translate }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form #feedbackForm="ngForm" (ngSubmit)="onSubmit()">
<ion-item>
<ion-label position="stacked">{{
'feedback.form.name.label' | translate
}}</ion-label>
<ion-input
placeholder="{{ 'feedback.form.name.placeholder' | translate }}"
[(ngModel)]="author.name"
name="name"
></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">{{
'feedback.form.type.label' | translate
}}</ion-label>
<ion-select
[(ngModel)]="message.name"
value="comment"
name="title"
interface="popover"
required="true"
>
<ion-select-option value="Comment">{{
'feedback.form.type.values.comment' | translate
}}</ion-select-option>
<ion-select-option value="Bug">{{
'feedback.form.type.values.bug' | translate
}}</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label position="stacked">{{
'feedback.form.email.label' | translate
}}</ion-label>
<ion-input
placeholder="{{ 'feedback.form.email.placeholder' | translate }}"
[(ngModel)]="author.email"
type="email"
name="email"
pattern="[A-Za-z0-9._%+-]{3,}@[a-zA-Z]{3,}([.]{1}[a-zA-Z]{2,}|[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,})"
></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">{{
'feedback.form.message.label' | translate
}}</ion-label>
<ion-textarea
[(ngModel)]="message.messageBody"
placeholder="{{ 'feedback.form.message.placeholder' | translate }}"
name="message"
required="true"
minlength="30"
autoGrow="true"
></ion-textarea>
</ion-item>
<ion-item>
<ion-label class="ion-text-wrap">{{
'feedback.form.termsAgree' | translate
}}</ion-label>
<ion-checkbox
color="primary"
slot="start"
[(ngModel)]="termsAgree"
name="termsAgree"
></ion-checkbox>
</ion-item>
<ion-button
type="submit"
color="primary"
expand="block"
[disabled]="!feedbackForm.valid || !termsAgree || submitSuccess"
>{{ 'feedback.form.submit' | translate }}</ion-button
>
<ion-card>
<ion-card-title>
<ion-button expand="block" fill="clear" (click)="toggleShowMetaData()">
<ng-container *ngIf="!showMetaData; else hide">{{
'feedback.form.protocolData.show' | translate
}}</ng-container>
<ng-template #hide>{{
'feedback.form.protocolData.hide' | translate
}}</ng-template>
</ion-button>
</ion-card-title>
<ion-card-content *ngIf="metaData && showMetaData">
<pre>{{ metaData | json }}</pre>
</ion-card-content>
</ion-card>
</form>
</ion-content>

View File

@@ -0,0 +1,6 @@
pre {
white-space: pre-wrap;
}
ion-button {
margin: 10px;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {IonicModule} from '@ionic/angular';
import {FeedbackPageComponent} from './feedback-page.component';
import {RouterModule, Routes} from '@angular/router';
import {TranslateModule} from '@ngx-translate/core';
import {MarkdownModule} from 'ngx-markdown';
const feedbackRoutes: Routes = [
{
path: 'feedback',
component: FeedbackPageComponent,
},
];
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild(feedbackRoutes),
TranslateModule,
MarkdownModule,
],
declarations: [FeedbackPageComponent],
})
export class FeedbackModule {}