toast todo things

This commit is contained in:
Baptiste Lemoine 2020-01-16 15:35:11 +01:00
parent 113609e945
commit 7b790e3cdc
16 changed files with 2603 additions and 2478 deletions

4580
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,7 @@
"@angular/language-service": "~8.2.14", "@angular/language-service": "~8.2.14",
"@types/jasmine": "~3.3.8", "@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.8", "@types/jasminewd2": "~2.0.8",
"@types/node": "~8.9.4", "@types/node": "^13.1.7",
"codelyzer": "^5.2.1", "codelyzer": "^5.2.1",
"jasmine-core": "~3.4.0", "jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1", "jasmine-spec-reporter": "~4.2.1",

View File

@ -1,20 +1,20 @@
<header style="text-align:center"> <header style="text-align:center" >
<a <a
[routerLink]="'home'" [routerLink]="'home'"
class="home_link" class="home_link"
aria-roledescription="home" aria-roledescription="home"
> >
<h1> <h1 >
<span class="logo_first">Frama</span> <span class="logo_first" >Frama</span >
<span class="logo_second">date</span> <span class="logo_second" >date</span >
</h1> </h1 >
<div class="legend">proposé par <div class="legend" >proposé par
<span class="legend_first">Frama</span> <span class="legend_first" >Frama</span >
<span class="legend_second">soft</span> <span class="legend_second" >soft</span >
</div> </div >
</a> </a >
<div id="translate_example"> <div id="translate_example" >
<div class="wrapper"> <div class="wrapper" >
<img <img
src="assets/img/icone-langue.svg" src="assets/img/icone-langue.svg"
alt="location icon" alt="location icon"
@ -37,20 +37,25 @@
value="d" value="d"
default default
class="select_language" class="select_language"
>{{"Language" | translate}}</option> >{{"Language" | translate}}</option >
<option value="en">English</option> <option value="en" >English</option >
<option value="fr">Français</option> <option value="fr" >Français</option >
</select> </select >
<span (click)="toggleMenu()" class="menu_label">Menu</span> <span
</div> (click)="toggleMenu()"
class="menu_label" >Menu</span >
</div >
</div> </div >
</header> </header >
<framadate-navigation *ngIf="menuVisible" [step]="step"></framadate-navigation>
<main> <main >
<router-outlet></router-outlet> <router-outlet ></router-outlet >
</main> </main >
<framadate-debugger></framadate-debugger> <framadate-debugger ></framadate-debugger >
<p-toast position="top-right"></p-toast> <framadate-navigation
*ngIf="menuVisible"
[step]="step" ></framadate-navigation >
<p-toast position="top-right" ></p-toast >

View File

@ -31,15 +31,18 @@ export const defaultDates = [
]; ];
export const defaultAnswers = [{ export const defaultAnswers = [{
id: 0, id: 0,
text: 'réponse de démo 1' text: 'réponse de démo 1',
pictureUrl: '',
}, },
{ {
id: 1, id: 1,
text: 'réponse 2' text: 'réponse 2',
pictureUrl: '',
}, },
{ {
id: 2, id: 2,
text: 'la réponse D' text: 'la réponse D',
pictureUrl: '',
}]; }];
/** /**
@ -54,6 +57,7 @@ export class PollConfig {
title = 'titre'; title = 'titre';
description = 'ma description'; description = 'ma description';
myName = 'mon pseudo'; myName = 'mon pseudo';
myComment = 'wouah trop bien framadate!';
myEmail: string = ""; myEmail: string = "";
// date specific poll, we have the choice to setup different hours (timeList) for all possible dates (dateList), or use the same hours for all dates // date specific poll, we have the choice to setup different hours (timeList) for all possible dates (dateList), or use the same hours for all dates
allowSeveralHours = 'false'; allowSeveralHours = 'false';

View File

@ -1,48 +1,52 @@
<div class="well debug"> <div class="well debug" >
<strong> <strong >
<h2 i18n> <h2 i18n >
infos de debug infos de debug
</h2> </h2 >
<span class="demo"> <span class="demo" >
{{"config.demo"|translate}} {{"config.demo"|translate}}
</span> </span >
</strong> </strong >
<ul> <ul >
<li> <li >
étape actuelle {{config.step}} / {{config.stepMax}} étape actuelle {{config.step}} / {{config.stepMax}}
</li> </li >
<li> <li >
formulaire valide : {{formIsValid}} formulaire valide : {{formIsValid}}
</li> </li >
<li> <li >
type de formulaire: {{config.pollType}} type de formulaire: {{config.pollType}}
</li> </li >
</ul> </ul >
<button <button
class="btn btn--primary" class="btn btn--primary"
i18n i18n
(click)="config.createPoll()" (click)="config.createPoll()"
> >
Envoyer le formulaire Envoyer le formulaire
</button> </button >
<button <button
class="btn btn--primary" class="btn btn--primary"
i18n i18n
(click)="config.getPollById(1, 'example password')" (click)="config.getPollById(1, 'example password')"
> >
get poll 1 get poll 1
</button> </button >
<button <button
class="btn btn--primary" class="btn btn--primary"
i18n i18n
(click)="config.getMyPolls( 'tktest@tktest.com')" (click)="config.getMyPolls( 'tktest@tktest.com')"
> >
get my polls get my polls
</button> </button >
<button class="btn btn--success" (click)="launchToast()"> <button
class="btn btn--success"
(click)="launchToast()" >
launch success toast launch success toast
</button> </button >
<a [routerLink]="'/vote/poll/id/3'" class="btn btn--success"> <a
[routerLink]="'/vote/poll/id/3'"
class="btn btn--success" >
See example of vote page See example of vote page
</a> </a >
</div> </div >

View File

@ -1,26 +1,40 @@
<div class="answers"> <div class="answers" >
<h1 i18n> <h1 i18n >
Choisir les propositions Choisir les propositions
</h1> </h1 >
<p class="subtitle" i18n> <p
Vous pouvez utiliser la syntaxe markdown class="subtitle"
</p> i18n >
Vous pouvez utiliser la syntaxe markdown, et naviguer entre les inputs avec les flèches du clavier.
</p >
<ol> <ol >
<li #answers *ngFor="let answer of config.answers; index as i;trackBy trackFunction" <li
class="answer-item"> #answers
*ngFor="let answer of config.answers; index as i;trackBy trackFunction"
class="answer-item" >
<button
class='btn btn--default'
title='ajouter une image'
(click)='showModalForPictureOfAnswer(answer)' >
<i class='fa fa-image' ></i >
</button >
<input <input
type="name" type="name"
class="answer" class="answer"
id='answer_{{answer.id}}'
[(ngModel)]="answer.text" [(ngModel)]="answer.text"
(keyup.enter)="addAnswer()" (keyup.enter)="addAnswer()"
(keyup)="navigateOrDelete($event,i)" (keyup)="navigateOrDelete($event,i)"
placeholder="réponse" placeholder="réponse"
> >
<button class="btn btn--alert" (click)="config.answers.splice(i,1)">X</button> <button
</li> class="btn btn--alert"
</ol> (click)="config.answers.splice(i,1)" >X
</button >
</li >
</ol >
<button <button
class="btn btn--primary btn--outline" class="btn btn--primary btn--outline"
@ -28,16 +42,19 @@
i18n i18n
> >
Ajouter une proposition Ajouter une proposition
</button> </button >
<br> <br >
<button <button
[routerLink]="'/step/resume'" [routerLink]="'/step/resume'"
class="btn btn--primary" class="btn btn--primary"
i18n i18n
> >
Voyons ce que ça donne Voyons ce que ça donne
</button> </button >
<a class="prev" i18n> <br >
<a
class="prev"
i18n >
Retour Retour
</a> </a >
</div> </div >

View File

@ -64,4 +64,9 @@ export class AnswersComponent extends BaseComponent implements OnInit, AfterView
this.focusOnAnswer(i + 1); this.focusOnAnswer(i + 1);
} }
} }
showModalForPictureOfAnswer(answer) {
// TODO
this.config.todo();
}
} }

View File

@ -11,7 +11,7 @@ import {ConfigService} from '../../services/config.service';
*/ */
export class BaseComponent implements OnInit { export class BaseComponent implements OnInit {
constructor(config: ConfigService) { constructor(private config: ConfigService) {
} }
ngOnInit() { ngOnInit() {
@ -20,11 +20,13 @@ export class BaseComponent implements OnInit {
checkValidity() { checkValidity() {
// TODO with form controls // TODO with form controls
this.config.todo();
return true; return true;
} }
displayErrorMessage() { displayErrorMessage() {
// TODO // TODO
this.config.todo();
return true; return true;
} }
} }

View File

@ -1,47 +1,97 @@
<div class="poll"> <div class="poll" >
<h1>{{pollConfigFetched.data.title}}</h1> <h1 >{{pollConfigFetched.data.title}}</h1 >
<p>{{pollConfigFetched.data.description}}</p> <p >{{pollConfigFetched.data.description}}</p >
<p class="creationDate">{{pollConfigFetched.data.creationDate.date}}</p> <p class="creationDate" >{{pollConfigFetched.data.creationDate.date}}</p >
<p class="expiracyDate">{{pollConfigFetched.data.creationDate.date}}</p> <p class="expiracyDate" >{{pollConfigFetched.data.creationDate.date}}</p >
<p class="votants"> <p class="votants" >
{{pollConfigFetched.stacks_count}} votants, {{pollConfigFetched.stacks_count}} votants,
{{pollConfigFetched.choices_count}} choix, {{pollConfigFetched.choices_count}} choix,
</p> </p >
</div> </div >
<section class="row name"> <section class="name" >
<label for="name">Votre nom :</label> <label for="name" >Votre nom :</label >
<input type="text" name="name" id="name" [(ngModel)]="config.myName"> <input
</section> type="text"
<div class="list-of-choices"> name="name"
<div *ngFor="let choice of pollConfigFetched.choices"> id="name"
<framadate-vote-choice [choice]="choice"></framadate-vote-choice> [(ngModel)]="config.myName" >
</div> </section >
</div> <div class="list-of-choices" >
<framadate-voting-graph></framadate-voting-graph> <div *ngFor="let choice of pollConfigFetched.choices" >
<framadate-voting-summary></framadate-voting-summary> <framadate-vote-choice [choice]="choice" ></framadate-vote-choice >
<div class="comments"> </div >
<h2 class="margin-top-x7">Laisser un commentaire</h2> </div >
<label for="crname">Votre nom :</label> <button
<input type="text" class="margin-btm-x3" name="crname" id="crname"> class='btn btn--primary btn-block'
<div> (click)='config.addVote()' >
<label for="comment">Votre commentaire :</label> <i class='fa fa-paper-plane' ></i > Envoyer
<textarea name="comment" id="comment"> </button >
</textarea> <framadate-voting-graph ></framadate-voting-graph >
</div> <framadate-voting-summary ></framadate-voting-summary >
<input type="submit" name="add-comment" class="btn btn--primary btn--outline" value="Ajouter mon commentaire"> <div class="comments" >
<framadate-voting-comment [comment]="c" *ngFor="let c of comments"></framadate-voting-comment> <h2 class="margin-top-x7" >Laisser un commentaire</h2 >
<label for="crname" >Votre nom :</label >
<input
type="text"
class="margin-btm-x3"
name="crname"
[(ngModel)]='config.myName'
id="crname" >
<div >
<label for="comment" >Votre commentaire :</label >
<br >
<textarea
name="comment"
id="comment"
[(ngModel)]='config.myComment'
>
</textarea >
</div >
<input
type="submit"
name="add-comment"
class="btn btn--primary btn--outline"
value="Ajouter mon commentaire"
(click)='config.addComment()' >
<framadate-voting-comment
[comment]="c"
*ngFor="let c of comments" >
</div> </framadate-voting-comment >
<div class="sharing"> </div >
<h3 class="margin-top-x8">Partager le sondage</h3> <div class="sharing" >
<label class="nobold text-14" for="copyLink">Pour partager le sondage, vous pouvez diffuser ce lien : <h3 class="margin-top-x8" >Partager le sondage
<code>
{{config.urlAdmin}} <i class='fa fa-share' ></i ></h3 >
</code> <p
</label> class="nobold text-14"
<input type="submit" name="copy-link" class=" btn btn--primary btn--outline" value="Copier le lien" id="copyLink"> for="copyLink" >Pour partager le sondage, vous pouvez diffuser ce lien :
<h3 class="margin-top-x6 margin-btm-x3">Exporter/Imprimer</h3> <a href='{{config.urlPublic}}' >
<input type="submit" name="export" class="margin-btm-x3 btn btn--primary btn--outline" value="Exporter en .csv" (click)="exportCSV()"> {{config.urlPublic}}
<input type="submit" name="copy-link" class="btn btn--primary btn--outline" value="Imprimer le sondage"> </a >
</div> </p >
<button
class=" btn btn--primary btn--outline"
[ngxClipboard]
[cbContent]="config.urlPublic"
id="copyLink" >
<i class='fa fa-copy' ></i >
{{"admin.copy_link" |translate}}
</button >
<h3 class="margin-top-x6 margin-btm-x3" >
Exporter/Imprimer
</h3 >
<input
type="submit"
name="export"
class="margin-btm-x3 btn btn--primary btn--outline"
value="Exporter en .csv"
(click)="config.exportCSV()" >
<input
type="submit"
name="copy-link"
class="btn btn--primary btn--outline"
value="Imprimer le sondage"
(click)="config.print()" >
</div >

View File

@ -23,7 +23,4 @@ export class PollDisplayComponent extends BaseComponent implements OnInit {
// store it in the poll property here // store it in the poll property here
} }
exportCSV() {
// TODO
}
} }

View File

@ -185,7 +185,6 @@ export class ConfigService extends PollConfig {
* @param err * @param err
*/ */
handleError(err: any) { handleError(err: any) {
// TODO handle a toast message
console.error('err', err); console.error('err', err);
this.loading = false; this.loading = false;
this.messageService.add({severity: 'warning', summary: "Erreur lors de l'appel ", detail: err.message}); this.messageService.add({severity: 'warning', summary: "Erreur lors de l'appel ", detail: err.message});
@ -294,7 +293,13 @@ export class ConfigService extends PollConfig {
* /api/v1/poll/{id}/vote * /api/v1/poll/{id}/vote
* @param voteStack * @param voteStack
*/ */
addVote(voteStack: any) { addVote(voteStack?: any) {
if (!voteStack) {
voteStack = {
pseudo: this.myName,
answers: this.answers
}
}
this.http.post( this.http.post(
`${this.baseHref}/poll/${this.pollId}/vote`, `${this.baseHref}/poll/${this.pollId}/vote`,
voteStack, voteStack,
@ -334,7 +339,13 @@ export class ConfigService extends PollConfig {
* /api/v1/poll/{id}/comment * /api/v1/poll/{id}/comment
* @param comment * @param comment
*/ */
addComment(comment: any) { addComment(comment?: any) {
if (!comment) {
comment = {
pseudo: this.myName,
comment: this.myComment,
}
}
this.http.post( this.http.post(
`${this.baseHref}/poll/${this.pollId}/comment`, `${this.baseHref}/poll/${this.pollId}/comment`,
comment, comment,
@ -345,6 +356,8 @@ export class ConfigService extends PollConfig {
summary: 'Commentaire Créé', summary: 'Commentaire Créé',
detail: 'Via MessageService' detail: 'Via MessageService'
}); });
// empty comment after success
this.myComment = '';
}, (e) => { }, (e) => {
this.handleError(e) this.handleError(e)
} }
@ -456,4 +469,38 @@ export class ConfigService extends PollConfig {
} }
); );
} }
/**
* export all the poll data available to the public as a CSV single file
*/
exportCSV() {
// TODO
const rows = [
["name1", "city1", "some other info"],
["name2", "city2", "more info"]
];
let csvContent = "data:text/csv;charset=utf-8,"
+ rows.map(e => e.join(",")).join("\n");
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", this.makeSlug() + "_export_" + new Date() + ".csv");
document.body.appendChild(link); // Required for FF
this.todo();
link.click(); // This will download the data file named "my_data.csv".
}
print() {
alert('TODO');
}
todo() {
this.messageService.add({
severity: 'info',
detail: "cette fonctionnalité n'est pas encore disponible. Venez en discuter sur framateam.org / Ux et design libre / Framasoft",
summary: "Work in progress",
});
}
} }

View File

@ -34,14 +34,14 @@
"dates": { "dates": {
"title": "Config especially for the dates", "title": "Config especially for the dates",
"hours_different": "I want to put", "hours_different": "I want to put",
"hours_each_day": "slots for each day", "hours_each_day": "slots for each day",
"multiple": { "multiple": {
"identical": "the same", "identical": "the same",
"different": "possibly different" "different": "possibly different"
}, },
"add": "Add a date choice", "add": "Add a date choice",
"add_time": "Add a schedule proposal", "add_time": "Add a schedule proposal",
"empty": "Empty", "empty": "Empty",
"count_dates": "choices of dates", "count_dates": "choices of dates",
"count_time": "choices of schedules", "count_time": "choices of schedules",
"add_interval": "Add a date interval", "add_interval": "Add a date interval",
@ -96,17 +96,17 @@
"validate_btn": "Create this poll!" "validate_btn": "Create this poll!"
}, },
"admin": { "admin": {
"choose_title": "The pool title is", "choose_title": "The pool title is",
"description": "and its description is", "description": "and its description is",
"info_section_title": "Pool informations", "info_section_title": "Pool informations",
"settings_section_title": "Settings", "settings_section_title": "Settings",
"votes_deletion_desc": "To start over from scratch, I can delete them all", "votes_deletion_desc": "To start over from scratch, I can delete them all",
"votes_deletion_btn": "Delete all the votes", "votes_deletion_btn": "Delete all the votes",
"comments_deletion_title": "Comments", "comments_deletion_title": "Comments",
"comments_deletion_desc": "If I wish, I can delete all the comments", "comments_deletion_desc": "If I wish, I can delete all the comments",
"comments_deletion_btn": "Delete all the comments", "comments_deletion_btn": "Delete all the comments",
"archiving_title": "Archiving", "archiving_title": "Archiving",
"archiving_desc": "This poll will no longer be editable from", "archiving_desc": "This poll will no longer be editable from",
"deletion": "Delete all", "deletion": "Delete all",
"deletion_desc": "In the case you want do delete everything, this button is for you:", "deletion_desc": "In the case you want do delete everything, this button is for you:",
"deletion_btn": "Delete the poll", "deletion_btn": "Delete the poll",

View File

@ -164,3 +164,8 @@ select, input, textarea {
color: $primary_color; color: $primary_color;
} }
} }
.btn-block {
display: block;
width: 100%;
}

View File

@ -1,18 +1,23 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": [
}, "node"
"files": [ ],
"src/main.ts", "typeRoots": [
"src/polyfills.ts" "./node_modules/@types"
], ]
"include": [ },
"src/**/*.ts" "files": [
], "src/main.ts",
"exclude": [ "src/polyfills.ts"
"src/test.ts", ],
"src/**/*.spec.ts" "include": [
] "src/**/*.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts"
]
} }

View File

@ -1,26 +1,30 @@
{ {
"compileOnSave": false, "compileOnSave": false,
"compilerOptions": { "node": true,
"baseUrl": "./", "compilerOptions": {
"outDir": "./dist/out-tsc", "baseUrl": "./",
"sourceMap": true, "outDir": "./dist/out-tsc",
"declaration": false, "sourceMap": true,
"downlevelIteration": true, "declaration": false,
"experimentalDecorators": true, "downlevelIteration": true,
"module": "esnext", "experimentalDecorators": true,
"moduleResolution": "node", "module": "esnext",
"importHelpers": true, "moduleResolution": "node",
"target": "es2018", "importHelpers": true,
"typeRoots": [ "target": "es2018",
"node_modules/@types" "types": [
], "node"
"lib": [ ],
"es2018", "typeRoots": [
"dom" "node_modules/@types"
] ],
}, "lib": [
"angularCompilerOptions": { "es2018",
"fullTemplateTypeCheck": true, "dom"
"strictInjectionParameters": true ]
} },
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
} }

View File

@ -1187,10 +1187,10 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.4.tgz#64db61e0359eb5a8d99b55e05c729f130a678b04" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.4.tgz#64db61e0359eb5a8d99b55e05c729f130a678b04"
integrity sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ== integrity sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==
"@types/node@~8.9.4": "@types/node@^13.1.7":
version "8.9.5" version "13.1.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.7.tgz#db51d28b8dfacfe4fb2d0da88f5eb0a2eca00675"
integrity sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ== integrity sha512-HU0q9GXazqiKwviVxg9SI/+t/nAsGkvLDkIdxz+ObejG2nX6Si00TeLqHMoS+a/1tjH7a8YpKVQwtgHuMQsldg==
"@types/q@^0.0.32": "@types/q@^0.0.32":
version "0.0.32" version "0.0.32"