forked from tykayn/funky-framadate-front
Merge branch 'several-steps-creation' into 'master'
5 steps to create a poll See merge request framasoft/framadate/funky-framadate-front!49
This commit is contained in:
commit
c1ec249e02
@ -40,7 +40,7 @@ build:
|
||||
stage: build
|
||||
script:
|
||||
- yarn install --pure-lockfile
|
||||
- npx ng build --prod
|
||||
- yarn run build:prod
|
||||
cache:
|
||||
policy: pull
|
||||
|
||||
|
@ -45,10 +45,12 @@
|
||||
"@fullcalendar/core": "^4.4.0",
|
||||
"@ngx-translate/core": "^12.1.2",
|
||||
"@ngx-translate/http-loader": "^5.0.0",
|
||||
"angular-date-value-accessor": "^1.0.2",
|
||||
"axios": "^0.19.2",
|
||||
"bulma": "^0.9.0",
|
||||
"bulma-switch": "^2.0.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"crypto": "^1.0.1",
|
||||
"crypto-js": "^4.0.0",
|
||||
"fork-awesome": "^1.1.7",
|
||||
"ng-keyboard-shortcuts": "^10.1.17",
|
||||
@ -57,6 +59,7 @@
|
||||
"ngx-markdown": "^9.0.0",
|
||||
"ngx-webstorage": "^5.0.0",
|
||||
"node-forge": "^0.10.0",
|
||||
"primeng": "^11.0.0",
|
||||
"quill": "^1.3.7",
|
||||
"rxjs": "^6.5.5",
|
||||
"rxjs-compat": "^6.5.5",
|
||||
@ -75,9 +78,9 @@
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"@babel/preset-typescript": "^7.9.0",
|
||||
"@compodoc/compodoc": "^1.1.11",
|
||||
"@types/crypto-js": "^4.0.0",
|
||||
"@types/jest": "^26.0.0",
|
||||
"@types/node": "^14.0.1",
|
||||
"@types/crypto-js": "^4.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^3.0.0",
|
||||
"@typescript-eslint/parser": "^3.0.0",
|
||||
"babel-jest": "^26.0.0",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { AfterViewInit, Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@ -11,6 +11,12 @@ import { slideInAnimation } from './shared/animations/main';
|
||||
import { FramaKeyboardShortcuts } from './shared/shortcuts/main';
|
||||
import { ShortcutEventOutput, ShortcutInput } from 'ng-keyboard-shortcuts';
|
||||
import { PollService } from './core/services/poll.service';
|
||||
import { Poll } from './core/models/poll.model';
|
||||
import { PollDTO } from './core/models/poll.DTO.model';
|
||||
import { PrimeNGConfig } from 'primeng/api';
|
||||
import { Language } from './core/enums/language.enum';
|
||||
import { ApiService } from './core/services/api.service';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -35,13 +41,15 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
private titleService: Title,
|
||||
private themeService: ThemeService,
|
||||
private pollService: PollService,
|
||||
private apiService: ApiService,
|
||||
private config: PrimeNGConfig,
|
||||
@Inject(DOCUMENT) private document: any,
|
||||
private languageService: LanguageService // private mockingService: MockingService
|
||||
) {}
|
||||
|
||||
printpath(parent: string, config: Route[]) {
|
||||
for (let i = 0; i < config.length; i++) {
|
||||
const route = config[i];
|
||||
console.info(parent + '/' + route.path);
|
||||
if (route.children) {
|
||||
const currentPath = route.path ? parent + '/' + route.path : parent;
|
||||
this.printpath(currentPath, route.children);
|
||||
@ -50,21 +58,29 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.languageService.getPrimeNgStrings().subscribe((resp) => {
|
||||
this.config.setTranslation(resp);
|
||||
});
|
||||
|
||||
this.printpath('', this.router.config);
|
||||
this.router.events.subscribe((evt) => {
|
||||
console.log('route changed', evt);
|
||||
|
||||
if (!(evt instanceof NavigationEnd)) {
|
||||
return;
|
||||
}
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
let mainelem = this.document.querySelector('#big_container main');
|
||||
console.log('mainelem', mainelem);
|
||||
window.scrollTo(0, mainelem.offsetTop);
|
||||
});
|
||||
|
||||
if (!environment.production) {
|
||||
this.appTitle += ' [DEV]';
|
||||
}
|
||||
|
||||
const loadedPoll = this.pollService._poll.getValue();
|
||||
let loadedPoll;
|
||||
if (this.pollService.poll) {
|
||||
loadedPoll = this.pollService.poll;
|
||||
}
|
||||
|
||||
this.titleService.setTitle(this.appTitle + ' - ' + loadedPoll.title);
|
||||
this.languageService.configureAndInitTranslations();
|
||||
@ -83,9 +99,12 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
this.themeClass = 'theme-light-watermelon';
|
||||
}
|
||||
});
|
||||
|
||||
// debug cors
|
||||
this.apiService.getAllAvailablePolls();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
console.log('this.shortcuts', this.shortcuts);
|
||||
this.shortcuts.push(
|
||||
{
|
||||
key: '?',
|
||||
@ -108,7 +127,6 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
preventDefault: true,
|
||||
}
|
||||
);
|
||||
console.log('this.shortcuts', this.shortcuts);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -117,10 +135,6 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
}
|
||||
}
|
||||
|
||||
public toggleSidebar(status: boolean): void {
|
||||
this.isSidebarOpened = status === true;
|
||||
}
|
||||
|
||||
prepareRoute(outlet: RouterOutlet) {
|
||||
return outlet && outlet.activatedRouteData && outlet.activatedRouteData.animation;
|
||||
}
|
||||
|
@ -26,5 +26,33 @@
|
||||
canal Matrix
|
||||
</a>
|
||||
</p>
|
||||
<div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<h3 class="title is-3">Framasoft</h3>
|
||||
L’association,Notre charte,Contacter Framasoft,Statistiques,État des services
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 class="title is-3">Communauté</h3>
|
||||
Framacolibri,Participer,Bénévolat valorisé,Partenaires,Charte de modération
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 class="title is-3">Framadate</h3>
|
||||
Entraide,Guides et astuces,Mentions légales,CGU,Crédits
|
||||
</div>
|
||||
<div class="column">
|
||||
<form action="#">
|
||||
<label for="subscribe_newsletter">
|
||||
<i class="fa fa-enveloppe"></i>
|
||||
Inscrivez-vous à la newsletter
|
||||
</label>
|
||||
<input type="text" class="input" id="subscribe_newsletter" />
|
||||
<button class="button is-outlined is-primary" (click)="subscribeToNewsletter()">
|
||||
S'inscrire
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
@ -11,4 +11,8 @@ export class FooterComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
subscribeToNewsletter() {
|
||||
alert('TODO');
|
||||
}
|
||||
}
|
||||
|
@ -123,4 +123,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
class="has-text-black"
|
||||
href="/#/administration/key/8Ubcg2YI99f69xz946cn4O64bQAebi11012P70trL5372qJ9JOem1Ks2fz7XD0b09p-8Ubcg2YI99f69xz946cn4O64bQAeb"
|
||||
>
|
||||
<i class="fa fa-hand-paper-o"></i> test admin link to edit poll
|
||||
</a>
|
||||
</header>
|
||||
|
@ -1,5 +1,20 @@
|
||||
<section class="hero">
|
||||
<div class="hero-body">
|
||||
<div class="columns presentation">
|
||||
<div class="column">
|
||||
<h2 class="title is-2">
|
||||
Organisez des évènements ou récoltez l’opinion de vos proches, simplement, librement.
|
||||
</h2>
|
||||
<p>
|
||||
Grâce à Framadate planifiez, organisez et prenez des décisions rapidement, simplement et sans
|
||||
inscription.
|
||||
</p>
|
||||
</div>
|
||||
<div class="column">
|
||||
<img src="assets/img/icone_home.png" alt="calendrier icone framadate" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="column">
|
||||
<section class="creation">
|
||||
@ -22,7 +37,9 @@
|
||||
*ngIf="environment.showDemoWarning"
|
||||
class="demo demo-warning well has-background-warning-light padded marged"
|
||||
>
|
||||
<h3 class="title is-3">
|
||||
Ce que l'on peut faire sur cette démo:
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
☑️ Créer un nouveau sondage
|
||||
@ -39,7 +56,9 @@
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="title is-3">
|
||||
Ce qu'on ne peut pas encore faire:
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
🚴️ mettre à jour son vote à un sondage
|
||||
@ -58,6 +77,8 @@
|
||||
<h1 class="title is-1 is-centered">
|
||||
{{ 'home.search_title' | translate }}
|
||||
</h1>
|
||||
|
||||
<img src="assets/img/where-is-it.jpg" alt="batman veut savoir où sont ses sondages" />
|
||||
<div class="poll-list">
|
||||
<ul>
|
||||
<li *ngFor="let p of storageService.userPolls">
|
||||
@ -75,7 +96,7 @@
|
||||
<form (ngSubmit)="searchMyPolls()">
|
||||
<div class="search-others">
|
||||
<label for="search_email">
|
||||
Je cherche d'autres sondages, qui correspondent à mon mail :
|
||||
{{ 'home.search_subtitle' | translate }}
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
@ -139,9 +160,11 @@
|
||||
<div class="column"></div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column"></div>
|
||||
<div class="column">
|
||||
<img src="assets/img/kind/classic.jpeg" alt="sondage date" />
|
||||
<img src="assets/img/kind/date.jpeg" alt="sondage date" />
|
||||
</div>
|
||||
<div class="column">
|
||||
<img src="assets/img/kind/classic.jpeg" alt="sondage classique" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
@import '../../../../styles/variables';
|
||||
|
||||
:host {
|
||||
text-align: center;
|
||||
margin-left: -2em;
|
||||
margin-right: -2em;
|
||||
a .fa {
|
||||
margin-right: 1ch;
|
||||
}
|
||||
@ -9,4 +13,7 @@
|
||||
.poll-list {
|
||||
margin: 2em 0;
|
||||
}
|
||||
.presentation {
|
||||
background: $secondary_color;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { StorageService } from '../../services/storage.service';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { ToastService } from '../../services/toast.service';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
@ -18,8 +19,11 @@ export class HomeComponent {
|
||||
@Inject(DOCUMENT) private document: any,
|
||||
public storageService: StorageService,
|
||||
public toastService: ToastService,
|
||||
public titleService: Title,
|
||||
private api: ApiService
|
||||
) {}
|
||||
) {
|
||||
this.titleService.setTitle(environment.appTitle + ' - Accueil ');
|
||||
}
|
||||
|
||||
searchMyPolls() {
|
||||
const email = this.storageService.vote_stack.owner.email;
|
||||
|
@ -6,8 +6,8 @@ export class Owner {
|
||||
public pseudo: string = 'pseudo',
|
||||
public email: string = '_nonexistent_contact@cipherbliss.com',
|
||||
public polls: Poll[] = [],
|
||||
public role?: UserRole,
|
||||
public modifier_token?: string,
|
||||
public created_at?: string
|
||||
public role: UserRole = UserRole.ADMIN,
|
||||
public modifier_token: string = '',
|
||||
public created_at: string = new Date().toISOString()
|
||||
) {}
|
||||
}
|
||||
|
46
src/app/core/models/poll.DTO.model.ts
Normal file
46
src/app/core/models/poll.DTO.model.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { Choice, ChoiceGroup } from './choice.model';
|
||||
import { DateChoice, TimeSlices } from './dateChoice.model';
|
||||
|
||||
export class PollDTO {
|
||||
menuVisible = true;
|
||||
expiracyDateDefaultInDays;
|
||||
deletionDateAfterLastModification;
|
||||
pollType: string = 'date'; // classic or dates
|
||||
title;
|
||||
description;
|
||||
myName;
|
||||
myComment = '';
|
||||
isAdmin; // when we create a poll; we are admin on it
|
||||
myVoteStack;
|
||||
myTempVoteStack;
|
||||
myEmail;
|
||||
myPolls; // list of retrieved polls from the backend api
|
||||
allowSeveralHours;
|
||||
visibility; // visible to one with the link:
|
||||
voteChoices = 'yes; maybe; no'; // possible answers to a vote choice: only "yes"; "yes; maybe; no"
|
||||
created_at;
|
||||
expirationDate; // expiracy date
|
||||
voteStackId; // id of the vote stack to update
|
||||
pollId; // id of the current poll when created. data given by the backend api
|
||||
pollSlug; // id of the current poll when created. data given by the backend api
|
||||
currentPoll; // current poll selected with createPoll or getPoll of ConfigService
|
||||
passwordAccess;
|
||||
password;
|
||||
customUrl; // custom slug in the url; must be unique
|
||||
customUrlIsUnique; // given by the backend
|
||||
urlSlugPublic;
|
||||
urlPublic;
|
||||
urlAdmin;
|
||||
adminKey; // key to change config of the poll
|
||||
owner_modifier_token; // key to change a vote stack
|
||||
canModifyAnswers; // bool for the frontend selector
|
||||
whoModifiesAnswers; // everybody; self; nobody (: just admin)
|
||||
whoCanChangeAnswers; // everybody; self; nobody (: just admin)
|
||||
dateList; // sets of days as strings; config to set identical time for days in a special days poll
|
||||
timeList; // ranges of time expressed as strings
|
||||
|
||||
answers;
|
||||
displayConfirmVoteModalAdmin;
|
||||
|
||||
constructor() {}
|
||||
}
|
@ -16,6 +16,8 @@ const apiBaseHref = environment.api.version[apiVersion].baseHref;
|
||||
|
||||
const apiEndpoints = environment.api.endpoints;
|
||||
|
||||
class PollDTO {}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
@ -36,16 +38,17 @@ export class ApiService {
|
||||
|
||||
this.axiosInstance = axios.create({ baseURL: apiBaseHref });
|
||||
this.axiosInstance.defaults.timeout = 2500;
|
||||
this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/json';
|
||||
this.axiosInstance.defaults.headers.post['Accept'] = 'application/json';
|
||||
this.axiosInstance.defaults.headers.post['Charset'] = 'UTF-8';
|
||||
// this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/json';
|
||||
// this.axiosInstance.defaults.headers.post['Accept'] = 'application/json';
|
||||
// this.axiosInstance.defaults.headers.post['Charset'] = 'UTF-8';
|
||||
// this.axiosInstance.defaults.headers.post['Accept-Charset'] = 'UTF-8';
|
||||
this.axiosInstance.defaults.headers.post['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
this.axiosInstance.defaults.headers.post['Referrer-Policy'] = 'origin-when-cross-origin';
|
||||
this.axiosInstance.defaults.headers.post['Access-Control-Allow-Origin'] = '*';
|
||||
this.axiosInstance.defaults.headers.post['Allow-Origin'] = '*';
|
||||
this.axiosInstance.defaults.headers.post['Access-Control-Allow-Headers'] =
|
||||
'Origin, X-Requested-With, Content-Type, Accept';
|
||||
// this.axiosInstance.defaults.headers.post['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
// this.axiosInstance.defaults.headers.post['Referrer-Policy'] = 'origin-when-cross-origin';
|
||||
// this.axiosInstance.defaults.headers.post['Access-Control-Allow-Origin'] = '*';
|
||||
// this.axiosInstance.defaults.headers.post['Control-Allow-Origin'] = '*';
|
||||
// this.axiosInstance.defaults.headers.post['Allow-Origin'] = '*';
|
||||
// this.axiosInstance.defaults.headers.post['Access-Control-Allow-Headers'] =
|
||||
// 'Origin, X-Requested-With, Content-Type, Accept';
|
||||
|
||||
console.log('this.axiosInstance.defaults.headers', this.axiosInstance.defaults.headers);
|
||||
}
|
||||
@ -66,25 +69,29 @@ export class ApiService {
|
||||
// Accept: 'application/json',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json',
|
||||
mode: 'no-cors',
|
||||
// mode: 'no-cors',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Accept,Accept-Language,Content-Language,Content-Type',
|
||||
// 'Access-Control-Allow-Origin': '*',
|
||||
};
|
||||
|
||||
return {
|
||||
const headersAxios = {
|
||||
headers: headerDict,
|
||||
body: bodyContent,
|
||||
};
|
||||
console.log('headersAxios', headersAxios);
|
||||
return headersAxios;
|
||||
}
|
||||
|
||||
public async createPoll(poll: Poll): Promise<Subscription> {
|
||||
/**
|
||||
*
|
||||
* @param poll
|
||||
*/
|
||||
public async createPoll(poll: PollDTO): Promise<Subscription> {
|
||||
// this.loaderService.setStatus(true);
|
||||
console.log('createPoll config', poll);
|
||||
console.log('apiservice createPoll config', poll);
|
||||
return this.axiosInstance.post(
|
||||
`${this.baseHref}${currentApiRoutes['api_new_poll']}`,
|
||||
poll,
|
||||
ApiService.makeHeaders()
|
||||
poll
|
||||
// ApiService.makeHeaders()
|
||||
);
|
||||
}
|
||||
|
||||
@ -134,10 +141,14 @@ export class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
/**
|
||||
* get all polls published by the API
|
||||
*/
|
||||
public async getAllAvailablePolls(): Promise<Poll[]> {
|
||||
// TODO: used for facilities in DEV, should be removed in production
|
||||
try {
|
||||
this.axiosInstance.options(this.pollsEndpoint);
|
||||
|
||||
const response: AxiosResponse<Poll[]> = await this.axiosInstance.get<Poll[]>(`${this.pollsEndpoint}`);
|
||||
return response?.data;
|
||||
} catch (error) {
|
||||
@ -145,10 +156,32 @@ export class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
public async getPollByCustomUrl(slug: string): Promise<Poll | undefined> {
|
||||
/**
|
||||
* get one poll by its admin key
|
||||
* @param admin_key
|
||||
*/
|
||||
public async getPollByAdminKey(admin_key: string): Promise<any | undefined> {
|
||||
try {
|
||||
console.log('fetch API : asking for poll with custom_url=' + slug);
|
||||
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(`${this.pollsEndpoint}/${slug}`);
|
||||
console.log('fetch API : asking for poll with admin_key=' + admin_key);
|
||||
const response: AxiosResponse<Poll> = await this.axiosInstance.get<any>(
|
||||
`${this.pollsEndpoint}/admin/${admin_key}`
|
||||
);
|
||||
return response && response.data && !Array.isArray(response.data) ? response.data : undefined;
|
||||
} catch (error) {
|
||||
if (error.response?.status === 404) {
|
||||
return undefined;
|
||||
} else {
|
||||
ApiService.handleError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async getPollByCustomUrl(custom_url: string): Promise<Poll | undefined> {
|
||||
try {
|
||||
console.log('fetch API : asking for poll with custom_url=' + custom_url);
|
||||
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(
|
||||
`${this.pollsEndpoint}/${custom_url}`
|
||||
);
|
||||
|
||||
return response && response.data && !Array.isArray(response.data) ? response.data : undefined;
|
||||
} catch (error) {
|
||||
@ -160,12 +193,12 @@ export class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
public async getPollByCustomUrlWithHash(slug: string, hash: string): Promise<Poll | undefined> {
|
||||
public async getPollByCustomUrlWithHash(custom_url: string, hash: string): Promise<Poll | undefined> {
|
||||
try {
|
||||
const response: AxiosResponse<Poll> = await this.axiosInstance.get<Poll>(
|
||||
`${this.pollsEndpoint}/${slug}/pass/${hash}`
|
||||
`${this.pollsEndpoint}/${custom_url}/pass/${hash}`
|
||||
);
|
||||
console.log('fetch API : asking for poll with custom_url=' + slug, { response });
|
||||
console.log('fetch API : asking for poll with custom_url=' + custom_url, { response });
|
||||
|
||||
return response && response.data && !Array.isArray(response.data) ? response.data : undefined;
|
||||
} catch (error) {
|
||||
@ -179,11 +212,11 @@ export class ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
public async getSlug(slug: string): Promise<boolean> {
|
||||
public async getSlug(custom_url: string): Promise<boolean> {
|
||||
try {
|
||||
// TODO: scenario should be : if we can get this custom_url, it exists. if not, it doesn't. It's just a GET.
|
||||
const response: AxiosResponse = await this.axiosInstance.get(
|
||||
`${this.pollsEndpoint}${this.slugsEndpoint}/${slug}`
|
||||
`${this.pollsEndpoint}${this.slugsEndpoint}/${custom_url}`
|
||||
);
|
||||
if (response?.status !== 404) {
|
||||
return false;
|
||||
@ -199,7 +232,7 @@ export class ApiService {
|
||||
|
||||
////////////
|
||||
// UPDATE //
|
||||
|
||||
////////////
|
||||
public async sendUpdateVoteStack(vote_stack: Stack) {
|
||||
try {
|
||||
return await this.axiosInstance.patch(
|
||||
|
@ -100,8 +100,6 @@ export class DateUtilitiesService {
|
||||
const ladate2 = this.addDaysToDate(1, today);
|
||||
const ladate3 = this.addDaysToDate(2, today);
|
||||
const ladate4 = this.addDaysToDate(3, today);
|
||||
const ladate5 = this.addDaysToDate(4, today);
|
||||
const ladate6 = this.addDaysToDate(5, today);
|
||||
|
||||
return [
|
||||
{
|
||||
@ -124,16 +122,6 @@ export class DateUtilitiesService {
|
||||
timeSlices: Object.create(defaultTimeOfDay),
|
||||
date_object: ladate4,
|
||||
},
|
||||
{
|
||||
literal: this.formateDateToInputStringNg(ladate5),
|
||||
timeSlices: Object.create(defaultTimeOfDay),
|
||||
date_object: ladate5,
|
||||
},
|
||||
{
|
||||
literal: this.formateDateToInputStringNg(ladate6),
|
||||
timeSlices: Object.create(defaultTimeOfDay),
|
||||
date_object: ladate6,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,10 @@ export class LanguageService {
|
||||
this.setLanguageOnInit();
|
||||
}
|
||||
|
||||
public getPrimeNgStrings() {
|
||||
return this.translate.get('calendar_widget');
|
||||
}
|
||||
|
||||
private setLanguageOnInit(): void {
|
||||
// set language from storage
|
||||
if (!this.translate.currentLang) {
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||
|
||||
import { Answer } from '../enums/answer.enum';
|
||||
import { Choice } from '../models/choice.model';
|
||||
import { Poll } from '../models/poll.model';
|
||||
import { Owner } from '../models/owner.model';
|
||||
import { ApiService } from './api.service';
|
||||
import { ToastService } from './toast.service';
|
||||
import { UserService } from './user.service';
|
||||
@ -14,7 +13,12 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { environment } from '../../../environments/environment';
|
||||
import { StorageService } from './storage.service';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { DateChoice, TimeSlices } from '../models/dateChoice.model';
|
||||
import { DateUtilitiesService } from './date.utilities.service';
|
||||
import { Owner } from '../models/owner.model';
|
||||
import { Stack } from '../models/stack.model';
|
||||
import { Vote } from '../models/vote.model';
|
||||
|
||||
@ -22,9 +26,29 @@ import { Vote } from '../models/vote.model';
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PollService implements Resolve<Poll> {
|
||||
_poll: BehaviorSubject<Poll | undefined> = new BehaviorSubject<Poll | undefined>(undefined);
|
||||
public _poll: BehaviorSubject<Poll | undefined> = new BehaviorSubject<Poll | undefined>(undefined);
|
||||
public readonly poll: Observable<Poll | undefined> = this._poll.asObservable();
|
||||
public form: FormGroup;
|
||||
public startDateInterval: string;
|
||||
public endDateInterval: string;
|
||||
public intervalDays: number = 1;
|
||||
public intervalDaysDefault = 7;
|
||||
public dateList: DateChoice[] = []; // sets of days as strings, config to set identical time for days in a special days poll
|
||||
public timeList: TimeSlices[] = []; // ranges of time expressed as strings
|
||||
public previousRouteName: string = '/administration';
|
||||
public nextRouteName: string = '/administration/step/2';
|
||||
public step_current: number = 1;
|
||||
public step_max: number = 5;
|
||||
public round: Function;
|
||||
public pass_hash: string;
|
||||
public admin_key: string;
|
||||
public urlPrefix: string = window.location.origin;
|
||||
public advancedDisplayEnabled = false;
|
||||
public showDateInterval = false;
|
||||
public allowSeveralHours = false;
|
||||
public richTextMode = false;
|
||||
public calendar: Date[] = [new Date()];
|
||||
public disabled_dates: Date[] = [];
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
@ -33,15 +57,132 @@ export class PollService implements Resolve<Poll> {
|
||||
private storageService: StorageService,
|
||||
private userService: UserService,
|
||||
private uuidService: UuidService,
|
||||
private dateUtils: DateUtilitiesService,
|
||||
private toastService: ToastService,
|
||||
private titleService: Title,
|
||||
private toastService: ToastService
|
||||
public DateUtilitiesService: DateUtilitiesService,
|
||||
public route: ActivatedRoute,
|
||||
@Inject(DOCUMENT) private document: any,
|
||||
private fb: FormBuilder
|
||||
) {
|
||||
this._poll.next(new Poll(null, 'titre', 'custom-title'));
|
||||
this.createFormGroup();
|
||||
|
||||
// fill in the next 3 days of the calendar date picker
|
||||
this.calendar = [
|
||||
this.DateUtilitiesService.addDaysToDate(1, new Date()),
|
||||
this.DateUtilitiesService.addDaysToDate(2, new Date()),
|
||||
this.DateUtilitiesService.addDaysToDate(3, new Date()),
|
||||
];
|
||||
// disable days before today
|
||||
for (let i = 1; i < 31; i++) {
|
||||
this.disabled_dates.push(this.DateUtilitiesService.addDaysToDate(-i, new Date()));
|
||||
}
|
||||
if (environment.autofill_creation) {
|
||||
this.setDemoValues();
|
||||
this.toastService.display('auto fill de création fait');
|
||||
}
|
||||
if (environment.autoSendNewPoll) {
|
||||
this.createPoll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add example values to the form for demo env
|
||||
*/
|
||||
setDemoValues(): void {
|
||||
this.form.patchValue({
|
||||
title: 'Mon titre de sondage du ' + this.DateUtilitiesService.formateDateToInputStringNg(new Date()),
|
||||
description: 'répondez SVP <3 ! *-* ',
|
||||
custom_url: this.uuidService.getUUID(),
|
||||
creatorPseudo: 'Chuck Norris',
|
||||
creatorEmail: 'chucknorris@example.com',
|
||||
isAboutDate: true,
|
||||
whoModifiesAnswers: 'everybody',
|
||||
whoCanChangeAnswers: 'everybody',
|
||||
isProtectedByPassword: false,
|
||||
richTextMode: false,
|
||||
areResultsPublic: true,
|
||||
expiresDaysDelay: environment.expiresDaysDelay,
|
||||
});
|
||||
this.automaticSlug();
|
||||
}
|
||||
|
||||
/**
|
||||
* set the poll slug from other data of the poll
|
||||
*/
|
||||
automaticSlug() {
|
||||
this.form.patchValue({ custom_url: this.makeSlug(this.form) });
|
||||
}
|
||||
|
||||
public createFormGroup() {
|
||||
let minlengthValidation = environment.production ? 12 : 0;
|
||||
let form = this.fb.group({
|
||||
title: ['mon titre de sondage', [Validators.required, Validators.minLength(minlengthValidation)]],
|
||||
creatorPseudo: ['', [Validators.required]],
|
||||
created_at: [new Date(), [Validators.required]],
|
||||
creatorEmail: ['', [Validators.required]],
|
||||
custom_url: [this.uuidService.getUUID(), [Validators.required]],
|
||||
description: ['', [Validators.required]],
|
||||
password: ['', []],
|
||||
choices: new FormArray([]),
|
||||
whoModifiesAnswers: ['', [Validators.required]],
|
||||
whoCanChangeAnswers: ['', [Validators.required]],
|
||||
isAboutDate: [true, [Validators.required]],
|
||||
expiresDaysDelay: [environment.expiresDaysDelay, []],
|
||||
maxCountOfAnswers: [300, []],
|
||||
isZeroKnoledge: [false, [Validators.required]],
|
||||
isProtectedByPassword: [false, [Validators.required]],
|
||||
isOwnerNotifiedByEmailOnNewVote: [true, [Validators.required]],
|
||||
isOwnerNotifiedByEmailOnNewComment: [true, [Validators.required]],
|
||||
areResultsPublic: [true, [Validators.required]],
|
||||
richTextMode: [false, [Validators.required]],
|
||||
isYesAnswerAvailable: [true, [Validators.required]],
|
||||
isMaybeAnswerAvailable: [true, [Validators.required]],
|
||||
isNoAnswerAvailable: [true, [Validators.required]],
|
||||
allowComments: [true, [Validators.required]],
|
||||
hasMaxCountOfAnswers: [300, [Validators.required]],
|
||||
useVoterUniqueLink: [false, [Validators.required]],
|
||||
voterEmailList: ['', []],
|
||||
allowNewDateTime: [true, [Validators.required]],
|
||||
});
|
||||
this.form = form;
|
||||
return form;
|
||||
}
|
||||
|
||||
/**
|
||||
* set default configs to the form
|
||||
*/
|
||||
public patchFormDefaultValues() {
|
||||
this.form.patchValue({
|
||||
title: 'mon titre de sondage',
|
||||
description: '',
|
||||
custom_url: this.uuidService.getUUID(),
|
||||
creatorPseudo: '',
|
||||
creatorEmail: '',
|
||||
isAboutDate: true,
|
||||
whoModifiesAnswers: 'everybody',
|
||||
whoCanChangeAnswers: 'everybody',
|
||||
isProtectedByPassword: false,
|
||||
richTextMode: false,
|
||||
areResultsPublic: true,
|
||||
expiresDaysDelay: environment.expiresDaysDelay,
|
||||
maxCountOfAnswers: 300,
|
||||
voterEmailList: '',
|
||||
password: '',
|
||||
});
|
||||
this.setDefaultDatesForInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* get a new slug from form title and creation date
|
||||
*/
|
||||
public updateSlug(): void {
|
||||
console.log('this.form.value', this.form.value);
|
||||
this.form.patchValue({ custom_url: this.makeSlug(this.form) });
|
||||
}
|
||||
|
||||
/**
|
||||
* auto fetch a poll when route is looking for one in the administration pattern
|
||||
* DO NOT USE - needs refacto
|
||||
* @param route
|
||||
* @param state
|
||||
*/
|
||||
@ -57,9 +198,9 @@ export class PollService implements Resolve<Poll> {
|
||||
) {
|
||||
if (this.pass_hash) {
|
||||
this.storageService.vote_stack.pass_hash = this.pass_hash;
|
||||
await this.loadPollBycustom_urlWithPasswordHash(wantedcustom_url, this.pass_hash);
|
||||
await this.loadPollByCustomUrlWithPasswordHash(wantedcustom_url, this.pass_hash);
|
||||
} else {
|
||||
await this.loadPollBycustom_url(wantedcustom_url);
|
||||
await this.loadPollByCustomUrl(wantedcustom_url);
|
||||
}
|
||||
}
|
||||
const loadedPoll = this._poll.getValue();
|
||||
@ -77,17 +218,19 @@ export class PollService implements Resolve<Poll> {
|
||||
*/
|
||||
getAllAvailablePolls(): void {
|
||||
const baseHref = environment.api.version.apiV1.baseHref;
|
||||
console.log('getAllAvailablePolls baseHref', baseHref);
|
||||
const headers = ApiService.makeHeaders();
|
||||
console.log('getAllAvailablePolls headers', headers);
|
||||
try {
|
||||
this.http.get(`${baseHref}/poll`, headers).subscribe((res: Observable<any>) => {
|
||||
console.log('getAllAvailablePolls res', res);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('getAllAvailablePolls e', e);
|
||||
console.log('getAllAvailablePolls e', e);
|
||||
}
|
||||
}
|
||||
|
||||
public async loadPollBycustom_url(custom_url: string): Promise<void> {
|
||||
public async loadPollByCustomUrl(custom_url: string): Promise<void> {
|
||||
if (custom_url) {
|
||||
const poll: Poll | undefined = await this.apiService.getPollByCustomUrl(custom_url);
|
||||
|
||||
@ -103,7 +246,7 @@ export class PollService implements Resolve<Poll> {
|
||||
}
|
||||
}
|
||||
|
||||
public async loadPollBycustom_urlWithPasswordHash(custom_url: string, hash: string): Promise<void> {
|
||||
public async loadPollByCustomUrlWithPasswordHash(custom_url: string, hash: string): Promise<void> {
|
||||
if (custom_url) {
|
||||
const poll: Poll | undefined = await this.apiService.getPollByCustomUrlWithHash(custom_url, hash);
|
||||
|
||||
@ -123,50 +266,243 @@ export class PollService implements Resolve<Poll> {
|
||||
* update poll and parse its fields
|
||||
* @param poll
|
||||
*/
|
||||
public updateCurrentPoll(poll: Poll): void {
|
||||
public updateCurrentPoll(poll: Poll): Poll {
|
||||
console.log('this.storageService.vote_stack.id', this.storageService.vote_stack.id);
|
||||
|
||||
if (!this.storageService.vote_stack.id || this.storageService.vote_stack.poll_custom_url !== poll.custom_url) {
|
||||
console.log('set base choices', poll.choices);
|
||||
// set the choices only the first time the poll loads, or if we changed the poll
|
||||
console.log(
|
||||
'this.storageService.vote_stack.poll_custom_url',
|
||||
this.storageService.vote_stack.poll_custom_url
|
||||
);
|
||||
// if (!this.storageService.vote_stack.id || this.storageService.vote_stack.poll_custom_url !== poll.custom_url) {
|
||||
// console.log('set base choices', poll.choices);
|
||||
// // set the choices only the first time the poll loads, or if we changed the poll
|
||||
// console.log(
|
||||
// 'this.storageService.vote_stack.poll_custom_url',
|
||||
// this.storageService.vote_stack.poll_custom_url
|
||||
// );
|
||||
// this.storageService.setChoicesForVoteStack(poll.choices);
|
||||
}
|
||||
// }
|
||||
|
||||
this.toastService.display('sondage bien mis à jour', 'success');
|
||||
this._poll.next(poll);
|
||||
console.log('next poll', poll);
|
||||
|
||||
this.storageService.setChoicesForVoteStack(poll.choices);
|
||||
|
||||
this.toastService.display(`sondage ${poll.title} bien mis à jour`, 'success');
|
||||
return poll;
|
||||
}
|
||||
|
||||
/**
|
||||
* make a uniq custom_url for the current poll creation
|
||||
* @param poll
|
||||
* add all the dates between the start and end dates in the interval section
|
||||
*/
|
||||
makecustom_url(poll: Poll): string {
|
||||
addIntervalOfDates(): void {
|
||||
const newIntervalArray = this.DateUtilitiesService.getDatesInRange(
|
||||
this.DateUtilitiesService.parseInputDateToDateObject(new Date(this.startDateInterval)),
|
||||
this.DateUtilitiesService.parseInputDateToDateObject(new Date(this.endDateInterval)),
|
||||
1
|
||||
);
|
||||
|
||||
const converted = [];
|
||||
newIntervalArray.forEach((element) => {
|
||||
converted.push({
|
||||
literal: element.literal,
|
||||
date_object: element.date_object,
|
||||
timeList: [],
|
||||
});
|
||||
});
|
||||
this.dateList = [...new Set(converted)];
|
||||
// add only dates that are not already present with a Set of unique items
|
||||
console.log('this.dateList', this.dateList);
|
||||
this.showDateInterval = false;
|
||||
|
||||
this.form.patchValue({ choices: this.dateList });
|
||||
|
||||
this.toastService.display(`les dates ont été ajoutées aux réponses possibles.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* handle keyboard shortcuts
|
||||
* @param $event
|
||||
* @param choice_number
|
||||
*/
|
||||
keyOnChoice($event: KeyboardEvent, choice_number: number): void {
|
||||
$event.preventDefault();
|
||||
|
||||
const lastChoice = this.choices.length - 1 === choice_number;
|
||||
// reset field with Ctrl + D
|
||||
// add a field with Ctrl + N
|
||||
// go to previous choice with arrow up
|
||||
// go to next choice with arrow down
|
||||
|
||||
if ($event.key == 'ArrowUp' && choice_number > 0) {
|
||||
this.focusOnChoice(choice_number - 1);
|
||||
}
|
||||
if ($event.key == 'ArrowDown') {
|
||||
// add a field if we are on the last choice
|
||||
if (lastChoice) {
|
||||
this.addChoice();
|
||||
this.toastService.display('choix ajouté par raccourci "flèche bas"');
|
||||
} else {
|
||||
this.focusOnChoice(choice_number + 1);
|
||||
}
|
||||
}
|
||||
if ($event.ctrlKey && $event.key == 'Backspace') {
|
||||
this.deleteChoiceField(choice_number);
|
||||
this.toastService.display('choix supprimé par raccourci "Ctrl + retour"');
|
||||
this.focusOnChoice(Math.min(choice_number - 1, 0));
|
||||
}
|
||||
if ($event.ctrlKey && $event.key == 'Enter') {
|
||||
// go to other fields
|
||||
const elem = this.document.querySelector('#creatorEmail');
|
||||
if (elem) {
|
||||
elem.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* change time spans
|
||||
*/
|
||||
addTime() {
|
||||
this.timeList.push({
|
||||
literal: '',
|
||||
});
|
||||
}
|
||||
|
||||
removeAllTimes() {
|
||||
this.timeList = [];
|
||||
}
|
||||
|
||||
resetTimes() {
|
||||
this.timeList = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* add a time period to a specific date choice,
|
||||
* focus on the new input
|
||||
* @param config
|
||||
* @param id
|
||||
*/
|
||||
addTimeToDate(config: any, id: number) {
|
||||
this.timeList.push({
|
||||
literal: '',
|
||||
});
|
||||
const selector = '[ng-reflect-choice_label="dateTime_' + id + '_Choices_' + (this.timeList.length - 1) + '"]';
|
||||
const elem = this.document.querySelector(selector);
|
||||
if (elem) {
|
||||
elem.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert form data to DTO to create a new poll, and store the admin key
|
||||
*/
|
||||
public createPoll(): Promise<any> {
|
||||
this.toastService.display('sending...');
|
||||
const newpoll = this.newPollFromForm();
|
||||
return this.apiService.createPoll(newpoll).then(
|
||||
(resp: any) => {
|
||||
console.log('poll created resp', resp);
|
||||
this.admin_key = resp.data.poll.admin_key;
|
||||
this.storageService.userPolls.push(resp.data.poll);
|
||||
},
|
||||
(error) => {
|
||||
this.toastService.display('BOOM, the createPoll went wrong');
|
||||
this.apiService.ousideHandleError(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* default interval of dates proposed is from today to 7 days more
|
||||
*/
|
||||
setDefaultDatesForInterval(): void {
|
||||
const dateCurrent = new Date();
|
||||
const dateJson = dateCurrent.toISOString();
|
||||
this.startDateInterval = dateJson.substring(0, 10);
|
||||
this.endDateInterval = this.DateUtilitiesService.addDaysToDate(this.intervalDaysDefault, dateCurrent)
|
||||
.toISOString()
|
||||
.substring(0, 10);
|
||||
this.form.patchValue({
|
||||
startDateInterval: this.startDateInterval,
|
||||
endDateInterval: this.endDateInterval,
|
||||
});
|
||||
this.countDays();
|
||||
}
|
||||
|
||||
askInitFormDefault(): void {
|
||||
this.initFormDefault(environment.autofill_creation);
|
||||
this.toastService.display('formulaire réinitialisé');
|
||||
}
|
||||
|
||||
countDays(): void {
|
||||
this.intervalDays = this.DateUtilitiesService.countDays(
|
||||
this.DateUtilitiesService.parseInputDateToDateObject(new Date(this.startDateInterval)),
|
||||
this.DateUtilitiesService.parseInputDateToDateObject(new Date(this.endDateInterval))
|
||||
);
|
||||
}
|
||||
|
||||
focusOnChoice(index): void {
|
||||
const selector = '#choice_label_' + index;
|
||||
const elem = this.document.querySelector(selector);
|
||||
if (elem) {
|
||||
elem.focus();
|
||||
}
|
||||
}
|
||||
|
||||
deleteChoiceField(index: number): void {
|
||||
if (this.choices.length !== 1) {
|
||||
this.choices.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
initFormDefault(showDemoValues = true): void {
|
||||
this.form = this.createFormGroup();
|
||||
this.patchFormDefaultValues();
|
||||
this.setDefaultDatesForInterval();
|
||||
|
||||
if (showDemoValues) {
|
||||
this.setDemoValues();
|
||||
}
|
||||
}
|
||||
|
||||
get choices(): FormArray {
|
||||
return this.form.get('choices') as FormArray;
|
||||
}
|
||||
|
||||
reinitChoices(): void {
|
||||
this.choices.setValue([]);
|
||||
}
|
||||
|
||||
addChoice(optionalLabel = ''): void {
|
||||
const newControlGroup = this.fb.group({
|
||||
label: this.fb.control('', [Validators.required]),
|
||||
imageUrl: ['', [Validators.required]],
|
||||
});
|
||||
|
||||
if (optionalLabel) {
|
||||
newControlGroup.patchValue({
|
||||
label: optionalLabel,
|
||||
imageUrl: 'mon url',
|
||||
});
|
||||
}
|
||||
this.choices.push(newControlGroup);
|
||||
|
||||
this.focusOnChoice(this.choices.length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* make a uniq slug for the current poll creation
|
||||
* @param form
|
||||
*/
|
||||
makeSlug(form: FormGroup): string {
|
||||
let str = '';
|
||||
const creation_date = new Date(poll.creation_date);
|
||||
str =
|
||||
creation_date.getFullYear() +
|
||||
form.value.created_at.getFullYear() +
|
||||
'_' +
|
||||
(creation_date.getMonth() + 1) +
|
||||
(form.value.created_at.getMonth() + 1) +
|
||||
'_' +
|
||||
creation_date.getDate() +
|
||||
form.value.created_at.getDate() +
|
||||
'_' +
|
||||
poll.owner.pseudo +
|
||||
form.value.creatorPseudo +
|
||||
'_' +
|
||||
poll.title;
|
||||
|
||||
return this.convertTextToSlug(str) + '-' + this.uuidService.getUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a text to a slug
|
||||
* @param str
|
||||
*/
|
||||
public convertTextToSlug(str: string): string {
|
||||
str = str.trim();
|
||||
form.value.title;
|
||||
str = str.replace(/^\s+|\s+$/g, ''); // trim
|
||||
str = str.toLowerCase();
|
||||
|
||||
@ -181,10 +517,25 @@ export class PollService implements Resolve<Poll> {
|
||||
.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
|
||||
.replace(/\s+/g, '-') // collapse whitespace and replace by -
|
||||
.replace(/-+/g, '-'); // collapse dashes
|
||||
return str;
|
||||
|
||||
return str + '-' + this.uuidService.getUUID();
|
||||
}
|
||||
|
||||
public async saveCurrentPoll(): Promise<void> {
|
||||
const pollUrl: Subscription = await this.apiService.createPoll(this._poll.getValue());
|
||||
// TODO: Maybe handle the url to update currentPoll according to backend response
|
||||
if (pollUrl) {
|
||||
this.toastService.display('Le sondage a été enregistré.');
|
||||
} else {
|
||||
this.toastService.display('Le sondage n’a été correctement enregistré, veuillez ré-essayer.');
|
||||
}
|
||||
}
|
||||
|
||||
public saveParticipation(choice: Choice, user: Owner, response: Answer): void {
|
||||
const currentPoll = this._poll.getValue();
|
||||
currentPoll.choices.find((c) => c.name === choice.name)?.updateParticipation(user, response);
|
||||
this.updateCurrentPoll(currentPoll);
|
||||
this.apiService.createParticipation(currentPoll.custom_url, choice.name, user.pseudo, response);
|
||||
this.toastService.display('Votre participation au sondage a été enregistrée.');
|
||||
}
|
||||
|
||||
@ -203,72 +554,85 @@ export class PollService implements Resolve<Poll> {
|
||||
this.toastService.display('Les commentaires de ce sondage ont été supprimés.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @description convert to API version 1 data transition object
|
||||
* @param form
|
||||
*/
|
||||
newPollFromForm(form: any): Poll {
|
||||
const newOwner = this.storageService.vote_stack.owner;
|
||||
public buildAnswersByChoiceLabelByPseudo(poll: Poll): Map<string, Map<string, Answer>> {
|
||||
const pseudos: Set<string> = new Set();
|
||||
poll.choices.forEach((choice: Choice) => {
|
||||
choice.participants.forEach((users: Set<Owner>) => {
|
||||
users.forEach((user: Owner) => {
|
||||
pseudos.add(user.pseudo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const newpoll = new Poll(newOwner, form.value.custom_url, form.value.title);
|
||||
const list = new Map<string, Map<string, Answer>>();
|
||||
pseudos.forEach((pseudo: string) => {
|
||||
list.set(
|
||||
pseudo,
|
||||
new Map<string, Answer>(
|
||||
poll.choices.map((choice: Choice) => {
|
||||
return [choice.name, undefined];
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
const pollKeys = Object.keys(newpoll);
|
||||
const formFields = Object.keys(form.value);
|
||||
newpoll.allowed_answers = ['yes'];
|
||||
poll.choices.forEach((choice: Choice) => {
|
||||
choice.participants.forEach((users: Set<Owner>, answer: Answer) => {
|
||||
users.forEach((user: Owner) => {
|
||||
list.get(user.pseudo).set(choice.name, answer);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
for (const pk of pollKeys) {
|
||||
if (formFields.indexOf(pk) !== -1) {
|
||||
const field = form.value[pk];
|
||||
newpoll[pk] = field;
|
||||
} else {
|
||||
console.log('manque pollKey', pk);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
if (form.value.isMaybeAnswerAvailable) {
|
||||
newpoll.allowed_answers.push('maybe');
|
||||
}
|
||||
if (form.value.isNoAnswerAvailable) {
|
||||
newpoll.allowed_answers.push('no');
|
||||
}
|
||||
newpoll.description = form.value.description;
|
||||
newpoll.has_several_hours = form.value.hasSeveralHours;
|
||||
newpoll.hasSeveralHours = form.value.hasSeveralHours;
|
||||
newpoll.max_count_of_answers = form.value.allowComments;
|
||||
newpoll.maxCountOfAnswers = form.value.maxCountOfAnswers;
|
||||
newpoll.password = form.value.password;
|
||||
newpoll.kind = form.value.kind;
|
||||
newpoll.allow_comments = form.value.allowComments;
|
||||
// merge choices from storage
|
||||
newpoll.choices = Object.assign([], this.storageService.choices);
|
||||
newpoll.dateChoices = Object.assign([], this.storageService.dateChoices);
|
||||
newpoll.timeSlices = Object.assign([], this.storageService.timeSlices);
|
||||
return newpoll;
|
||||
public getParticipationUrlFromForm(): string {
|
||||
return `${environment.frontDomain}#/poll/${this.form.value.custom_url}/consultation`;
|
||||
}
|
||||
|
||||
public getAdministrationUrl(): string {
|
||||
let url = '';
|
||||
if (this._poll && this._poll.getValue) {
|
||||
const polltemp = this._poll.getValue();
|
||||
if (polltemp) {
|
||||
url = `${environment.frontDomain}#/poll/admin/${polltemp.admin_key}`;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
public getAdministrationUrlFromForm(): string {
|
||||
// admin_key is filled after creation
|
||||
// example http://localhost:4200/#/administration/key/8Ubcg2YI99f69xz946cn4O64bQAeb
|
||||
|
||||
return `${environment.frontDomain}#/administration/key/${this.admin_key}`;
|
||||
}
|
||||
|
||||
public getParticipationUrl(): string {
|
||||
// http://localhost:4200/#/poll/dessin-anime/consultation
|
||||
|
||||
// TODO handle secure access
|
||||
// http://localhost:4200/#/poll/citron/consultation/secure/1c01ed9c94fc640a1be864f197ff808c
|
||||
|
||||
let url = '';
|
||||
if (this._poll && this._poll.getValue) {
|
||||
const polltemp = this._poll.getValue();
|
||||
if (polltemp) {
|
||||
url = `${environment.frontDomain}#/poll/${polltemp.custom_url}/consultation`;
|
||||
}
|
||||
} else {
|
||||
url = `${environment.frontDomain}#/poll/${this.form.value.custom_url}/consultation`;
|
||||
}
|
||||
|
||||
// TODO handle pass access
|
||||
return url;
|
||||
}
|
||||
|
||||
public getAdministrationUrl(): string {
|
||||
// http://localhost:4200/#/admin/9S75b70ECXI5J5xDc058d3H40H9r2CHfO0Kj8T02EK2U8rY8fYTn-eS659j2Dhp794Oa6R1b9V70e3WGaE30iD9h45zwdm76C85SWB4LcUCrc7e0Ncc0
|
||||
|
||||
let url = '';
|
||||
if (this._poll && this._poll.getValue) {
|
||||
const polltemp = this._poll.getValue();
|
||||
if (polltemp) {
|
||||
url = `${environment.frontDomain}#/admin/${polltemp.admin_key}`;
|
||||
}
|
||||
} else {
|
||||
url = `${environment.frontDomain}#/admin/${this.form.value.admin_key}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* enrich vote stack with missing default votes
|
||||
* @param vote_stack
|
||||
@ -297,4 +661,78 @@ export class PollService implements Resolve<Poll> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
convertCalendarDatesToChoices(array_dates) {
|
||||
return array_dates;
|
||||
}
|
||||
|
||||
patchFormWithPoll(poll: Poll) {
|
||||
this.form.patchValue({
|
||||
...poll,
|
||||
isAboutDate: poll.kind == 'date',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description convert to API version 1 data transition object
|
||||
*/
|
||||
newPollFromForm(): Poll {
|
||||
let form = this.form;
|
||||
console.log('this.form.value', this.form.value);
|
||||
const newOwner = this.storageService.vote_stack.owner;
|
||||
|
||||
const newpoll = new Poll(newOwner, form.value.custom_url, form.value.title);
|
||||
|
||||
const pollKeys = Object.keys(newpoll);
|
||||
const formFields = Object.keys(form.value);
|
||||
newpoll.allowed_answers = [];
|
||||
|
||||
// comparer les champs de formulaire avec le DTO de création de sondage
|
||||
for (const pk of pollKeys) {
|
||||
if (formFields.indexOf(pk) !== -1) {
|
||||
const field = form.value[pk];
|
||||
newpoll[pk] = field;
|
||||
} else {
|
||||
// console.log('manque pollKey', pk);
|
||||
}
|
||||
}
|
||||
|
||||
if (form.value.isYesAnswerAvailable) {
|
||||
newpoll.allowed_answers.push('yes');
|
||||
}
|
||||
if (form.value.isMaybeAnswerAvailable) {
|
||||
newpoll.allowed_answers.push('maybe');
|
||||
}
|
||||
if (form.value.isNoAnswerAvailable) {
|
||||
newpoll.allowed_answers.push('no');
|
||||
}
|
||||
newpoll.description = form.value.description;
|
||||
newpoll.has_several_hours = form.value.hasSeveralHours;
|
||||
newpoll.max_count_of_answers = form.value.maxCountOfAnswers;
|
||||
newpoll.maxCountOfAnswers = form.value.maxCountOfAnswers;
|
||||
newpoll.password = form.value.password;
|
||||
newpoll.kind = form.value.isAboutDate ? 'date' : 'classic';
|
||||
newpoll.allow_comments = form.value.allowComments;
|
||||
// merge choices from storage
|
||||
if (form.value.isAboutDate) {
|
||||
// convert calendar picker dates
|
||||
console.log('this.calendar', this.calendar);
|
||||
|
||||
for (let elem of this.calendar) {
|
||||
console.log('elem', elem);
|
||||
let converted_day = {
|
||||
literal: this.DateUtilitiesService.formateDateToInputStringNg(elem),
|
||||
timeSlices: [],
|
||||
date_object: elem,
|
||||
};
|
||||
newpoll.dateChoices.push(converted_day);
|
||||
}
|
||||
console.log('newpoll.dateChoices', newpoll.dateChoices);
|
||||
}
|
||||
newpoll.choices = Object.assign([], this.storageService.choices);
|
||||
// newpoll.dateChoices = Object.assign([], this.storageService.dateChoices);
|
||||
newpoll.timeSlices = Object.assign([], this.storageService.timeSlices);
|
||||
console.log('newpoll', newpoll);
|
||||
return newpoll;
|
||||
}
|
||||
}
|
||||
|
@ -65,16 +65,16 @@ export class PollUtilitiesService {
|
||||
* @param bodyContent
|
||||
*/
|
||||
makeHeaders(bodyContent?: any) {
|
||||
const headerDict = {
|
||||
Charset: 'UTF-8',
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
};
|
||||
// const headerDict = {
|
||||
// Charset: 'UTF-8',
|
||||
// 'Content-Type': 'application/json',
|
||||
// Accept: 'application/json',
|
||||
// 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
// 'Access-Control-Allow-Origin': '*',
|
||||
// };
|
||||
|
||||
return {
|
||||
headers: headerDict,
|
||||
headers: [],
|
||||
body: bodyContent,
|
||||
};
|
||||
}
|
||||
|
@ -46,18 +46,13 @@ export class StorageService {
|
||||
public choices: Choice[] = [];
|
||||
|
||||
constructor(public dateUtilities: DateUtilitiesService, private toastService: ToastService) {
|
||||
if (environment.autofill) {
|
||||
this.toastService.display('autofill des sondages utilisateur');
|
||||
if (environment.autofill_participation) {
|
||||
this.userPolls.push(new Poll(new Owner(), 'Démo: Anniversaire de tonton Patrick', 'aujourdhui-ou-demain'));
|
||||
this.userPolls.push(new Poll(new Owner(), 'Démo: Atelier cuisine du quartier', 'aujourdhui-ou-demain'));
|
||||
this.userPolls.push(
|
||||
new Poll(new Owner(), 'Démo: Réunion du département des chatons', 'aujourdhui-ou-demain')
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.dateChoices.length) {
|
||||
this.dateChoices = this.dateUtilities.makeDefaultDateChoices();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,15 +65,16 @@ export class StorageService {
|
||||
if (!this.vote_stack.id) {
|
||||
this.vote_stack = new Stack();
|
||||
|
||||
console.log('choices_list', choices_list);
|
||||
for (const choice of choices_list) {
|
||||
if (environment.autofill) {
|
||||
console.log('autofill au hasard des votes à ce sondage');
|
||||
this.toastService.display('autofill au hasard des votes à ce sondage');
|
||||
const defaultvalue = Math.random() > 0.75 ? 'yes' : '';
|
||||
this.vote_stack.votes.push(new Vote(choice.id, defaultvalue));
|
||||
} else {
|
||||
// if (environment.autofill_participation) {
|
||||
// console.log('autofill au hasard des votes à ce sondage');
|
||||
// this.toastService.display('autofill au hasard des votes à ce sondage');
|
||||
// const defaultvalue = Math.random() > 0.75 ? 'yes' : '';
|
||||
// this.vote_stack.votes.push(new Vote(choice.id, defaultvalue));
|
||||
// } else {
|
||||
this.vote_stack.votes.push(new Vote(choice.id));
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,34 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { AdministrationComponent } from './administration.component';
|
||||
import { NamingComponent } from './naming/naming.component';
|
||||
import { StepTwoComponent } from './form/steps/step-two/step-two.component';
|
||||
import { StepThreeComponent } from './form/steps/step-three/step-three.component';
|
||||
import { StepFourComponent } from './form/steps/step-four/step-four.component';
|
||||
import { StepFiveComponent } from './form/steps/step-five/step-five.component';
|
||||
import { StepOneComponent } from './form/steps/step-one/step-one.component';
|
||||
import { SuccessComponent } from './success/success.component';
|
||||
import { AdminConsultationComponent } from './consultation/consultation.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: AdministrationComponent, data: { animation: 'AdminPage' } },
|
||||
{ path: 'naming', component: NamingComponent },
|
||||
{
|
||||
path: '',
|
||||
component: AdministrationComponent,
|
||||
},
|
||||
{ path: 'key/:admin_key', component: AdminConsultationComponent },
|
||||
{
|
||||
path: 'step',
|
||||
children: [
|
||||
{ path: '1', component: StepOneComponent },
|
||||
{ path: '2', component: StepTwoComponent },
|
||||
{ path: '3', component: StepThreeComponent },
|
||||
{ path: '4', component: StepFourComponent },
|
||||
{ path: '5', component: StepFiveComponent },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'success',
|
||||
component: SuccessComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -20,7 +20,7 @@ export class AdministrationComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.routeSubscription = this.route.data.subscribe((data: { poll: Poll }) => {
|
||||
console.log('data', data);
|
||||
console.log('routeSubscription data', data);
|
||||
if (data.poll) {
|
||||
this.poll = data.poll;
|
||||
}
|
||||
|
@ -9,6 +9,12 @@ import { AdministrationComponent } from './administration.component';
|
||||
import { StepperComponent } from './stepper/stepper.component';
|
||||
import { NamingComponent } from './naming/naming.component';
|
||||
import { FormComponent } from './form/form.component';
|
||||
import { StepOneComponent } from './form/steps/step-one/step-one.component';
|
||||
import { StepTwoComponent } from './form/steps/step-two/step-two.component';
|
||||
import { StepThreeComponent } from './form/steps/step-three/step-three.component';
|
||||
import { StepFourComponent } from './form/steps/step-four/step-four.component';
|
||||
import { StepFiveComponent } from './form/steps/step-five/step-five.component';
|
||||
import { CalendarModule } from 'primeng/calendar';
|
||||
import { SuccessComponent } from './success/success.component';
|
||||
import { DateSelectComponent } from './form/date-select/date-select.component';
|
||||
import { TextSelectComponent } from './form/text-select/text-select.component';
|
||||
@ -21,6 +27,7 @@ import { IntervalComponent } from './form/date/interval/interval.component';
|
||||
import { DayListComponent } from './form/date/list/day/day-list.component';
|
||||
import { PickerComponent } from './form/date/picker/picker.component';
|
||||
import { TimeListComponent } from './form/date/list/time/time-list.component';
|
||||
import { AdminConsultationComponent } from './consultation/consultation.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -34,14 +41,22 @@ import { TimeListComponent } from './form/date/list/time/time-list.component';
|
||||
KindSelectComponent,
|
||||
BaseConfigComponent,
|
||||
AdvancedConfigComponent,
|
||||
StepOneComponent,
|
||||
StepTwoComponent,
|
||||
StepThreeComponent,
|
||||
StepFourComponent,
|
||||
StepFiveComponent,
|
||||
SuccessComponent,
|
||||
IntervalComponent,
|
||||
DayListComponent,
|
||||
PickerComponent,
|
||||
TimeListComponent,
|
||||
AdminConsultationComponent,
|
||||
],
|
||||
imports: [
|
||||
AdministrationRoutingModule,
|
||||
CommonModule,
|
||||
CalendarModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
FormsModule,
|
||||
|
@ -0,0 +1,16 @@
|
||||
<div class="admin-consultation min-height padded">
|
||||
<h2 class="title is-2">Consulter le sondage</h2>
|
||||
<button class="btn is-primary" [routerLink]="'/administration'">
|
||||
<i class="fa fa-pencil"></i>
|
||||
modifier
|
||||
</button>
|
||||
<div>
|
||||
<h2>{{ form.value.title }}</h2>
|
||||
|
||||
<div *ngIf="poll">
|
||||
<h2>{{ poll.title }}</h2>
|
||||
|
||||
Créé le {{ poll.created_at | date }} par {{ poll.owner.pseudo }}, {{ poll.owner.email }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ConsultationComponent } from './consultation.component';
|
||||
|
||||
describe('ConsultationComponent', () => {
|
||||
let component: ConsultationComponent;
|
||||
let fixture: ComponentFixture<ConsultationComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ConsultationComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ConsultationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { PollService } from '../../../core/services/poll.service';
|
||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||
import { ApiService } from '../../../core/services/api.service';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { Poll } from '../../../core/models/poll.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-consultation',
|
||||
templateUrl: './consultation.component.html',
|
||||
styleUrls: ['./consultation.component.scss'],
|
||||
})
|
||||
export class AdminConsultationComponent implements OnInit {
|
||||
private admin_key: string;
|
||||
public form: FormGroup;
|
||||
public poll: any;
|
||||
|
||||
constructor(
|
||||
private pollService: PollService,
|
||||
private apiService: ApiService,
|
||||
private _Activatedroute: ActivatedRoute,
|
||||
private router: Router
|
||||
) {
|
||||
this.poll = this.pollService._poll.getValue();
|
||||
this.form = this.pollService.form;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._Activatedroute.paramMap.subscribe((params: ParamMap) => {
|
||||
this.admin_key = params.get('admin_key');
|
||||
if (!this.admin_key) {
|
||||
this.router.navigate(['page-not-found']);
|
||||
}
|
||||
this.apiService.getPollByAdminKey(this.admin_key).then(
|
||||
(res) => {
|
||||
this.pollService.updateCurrentPoll(res.poll);
|
||||
this.form = this.pollService.form;
|
||||
this.poll = this.pollService._poll.getValue();
|
||||
console.log('formulaire patché', this.pollService.form, this.pollService.poll);
|
||||
},
|
||||
(err) => {
|
||||
if (!this.admin_key) {
|
||||
this.router.navigate(['page-not-found']);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
<form [formGroup]="form" class="box">
|
||||
<fieldset class="complete well">
|
||||
<h2>{{ 'creation.advanced' | translate }}</h2>
|
||||
<label for="descr">Description (optionnel)</label>
|
||||
<br />
|
||||
<textarea
|
||||
@ -11,32 +10,20 @@
|
||||
formControlName="description"
|
||||
required
|
||||
></textarea>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="description.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="description.value = ''"
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
|
||||
<br />
|
||||
|
||||
<label for="custom_url">
|
||||
Url personnalisée pour les participants
|
||||
<i class="fa fa-close"></i>
|
||||
</label>
|
||||
<br />
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="form.controls.custom_url.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="form.patchValue({ custom_url: '' })"
|
||||
></button>
|
||||
(click)="form.patchValue({ custom_url: pollService.makeSlug(form) })"
|
||||
>
|
||||
<i class="fa fa-recycle"></i> régénérer
|
||||
</button>
|
||||
<input #custom_url matInput id="custom_url" placeholder="Url" formControlName="custom_url" required />
|
||||
<br />
|
||||
<div appearance="outline" class="is-not-flex">
|
||||
@ -52,16 +39,6 @@
|
||||
formControlName="expiresDaysDelay"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="expiresDaysDelay.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="expiresDaysDelay.value = ''"
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
</div>
|
||||
<mat-checkbox class="is-not-flex" formControlName="areResultsPublic">
|
||||
Les participants pourront consulter les résultats
|
||||
@ -75,16 +52,26 @@
|
||||
Le sondage sera protégé par un mot de passe
|
||||
</mat-checkbox>
|
||||
<br />
|
||||
<div class="password-box" *ngIf="form.value.isProtectedByPassword">
|
||||
<input
|
||||
*ngIf="form.value.isProtectedByPassword"
|
||||
#password
|
||||
id="password"
|
||||
matInput
|
||||
type="password"
|
||||
[type]="displayClearPassword ? 'text' : 'password'"
|
||||
placeholder="password"
|
||||
formControlName="password"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
class="button"
|
||||
[ngClass]="{ 'is-primary': displayClearPassword, 'is-info': !displayClearPassword }"
|
||||
(click)="displayClearPassword = !displayClearPassword"
|
||||
>
|
||||
voir
|
||||
<i class="fa fa-eye" *ngIf="!displayClearPassword"></i>
|
||||
<i class="fa fa-eye-slash" *ngIf="displayClearPassword"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h3 class="title is-3">
|
||||
<i class="fa fa-envelope-open"></i>
|
||||
@ -103,20 +90,19 @@
|
||||
Réponses proposées
|
||||
</h3>
|
||||
|
||||
<img class="image is-24x24 pull-right" src="assets/img/icon_voter_YES.svg" />
|
||||
<img class="image is-24x24 pull-right" src="assets/img/icon_voter_MAYBE.svg" />
|
||||
<img class="image is-24x24 pull-right" src="assets/img/icon_voter_NO.svg" />
|
||||
|
||||
<mat-checkbox class="is-not-flex" formControlName="isYesAnswerAvailable">
|
||||
La réponse « oui » sera disponible
|
||||
<img class="image is-24x24 pull-right" src="assets/img/icon_voter_YES.svg" />
|
||||
</mat-checkbox>
|
||||
<br />
|
||||
<mat-checkbox class="is-not-flex" formControlName="isMaybeAnswerAvailable">
|
||||
La réponse « peut-être » sera disponible
|
||||
<img class="image is-24x24 pull-right" src="assets/img/icon_voter_MAYBE.svg" />
|
||||
</mat-checkbox>
|
||||
<br />
|
||||
<mat-checkbox class="is-not-flex" formControlName="isNoAnswerAvailable">
|
||||
La réponse « non » sera disponible
|
||||
<img class="image is-24x24 pull-right" src="assets/img/icon_voter_NO.svg" />
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<h3 class="title is-3">
|
||||
@ -128,7 +114,7 @@
|
||||
</mat-checkbox>
|
||||
<br />
|
||||
<mat-checkbox class="is-not-flex" formControlName="hasMaxCountOfAnswers">
|
||||
Nombre de réponses limitées à ce nombre
|
||||
Nombre de réponses limitées à ce nombre. Utile pour réserver des places à un évènement.
|
||||
</mat-checkbox>
|
||||
<input
|
||||
*ngIf="form.value.hasMaxCountOfAnswers"
|
||||
@ -142,16 +128,14 @@
|
||||
/>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<fieldset class="work-in-progress">
|
||||
<h2 class="title is-2">
|
||||
<i class="fa fa-wikidata"></i>
|
||||
Fonctionnalités pas encore disponibles:
|
||||
</h2>
|
||||
<app-wip-todo></app-wip-todo>
|
||||
|
||||
<div>
|
||||
<mat-checkbox class="is-not-flex" formControlName="useVoterUniqueLink">
|
||||
Spécifier un lien unique de vote à des participants définis
|
||||
Spécifier un <strong> lien unique de vote</strong> à des participants définis par leur email
|
||||
</mat-checkbox>
|
||||
<p>
|
||||
lister les email des participants et leur fournir un lien unique pour voter à chacun, au lieu d'un lien
|
||||
@ -174,4 +158,5 @@
|
||||
Les informations du sondage seront chiffrés en base de données
|
||||
</mat-checkbox>
|
||||
</fieldset>
|
||||
<app-errors-list [form]="form"></app-errors-list>
|
||||
</form>
|
||||
|
@ -1,3 +1,19 @@
|
||||
@import '../../../../../styles/variables';
|
||||
|
||||
.title {
|
||||
margin-top: 2em;
|
||||
}
|
||||
.mat-checkbox {
|
||||
img {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
.button .fa {
|
||||
margin: 1em;
|
||||
}
|
||||
input,
|
||||
textarea {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 1.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Poll } from '../../../../core/models/poll.model';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { PollService } from '../../../../core/services/poll.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-advanced-config',
|
||||
@ -11,11 +12,12 @@ import { environment } from 'src/environments/environment';
|
||||
export class AdvancedConfigComponent implements OnInit {
|
||||
public urlPrefix = '/participation/';
|
||||
public environment = environment;
|
||||
public displayClearPassword = false;
|
||||
@Input()
|
||||
public poll?: Poll;
|
||||
@Input()
|
||||
public form: FormGroup;
|
||||
constructor() {}
|
||||
constructor(public pollService: PollService) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#title {
|
||||
display: block;
|
||||
width: 80%;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export class BaseConfigComponent {
|
||||
) {}
|
||||
|
||||
public updateSlug(): void {
|
||||
const newValueFormatted = this.pollService.convertTextToSlug(this.form.value.title);
|
||||
const newValueFormatted = this.pollService.makeSlug(this.pollService.form);
|
||||
console.log('newValueFormatted', newValueFormatted);
|
||||
this.form.patchValue({ custom_url: newValueFormatted });
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ export class IntervalComponent implements OnInit {
|
||||
this.intervalDays = this.dateUtilities.countDays(
|
||||
this.startDateInterval,
|
||||
this.endDateInterval
|
||||
// this.dateUtilities.parseInputDateToDateObject(this.startDateIntervalString),
|
||||
// this.dateUtilities.parseInputDateToDateObject(this.endDateIntervalString)
|
||||
// this.DateUtilitiesService.parseInputDateToDateObject(this.startDateIntervalString),
|
||||
// this.DateUtilitiesService.parseInputDateToDateObject(this.endDateIntervalString)
|
||||
);
|
||||
console.log('this.intervalDays ', this.intervalDays);
|
||||
}
|
||||
|
@ -1,101 +1,9 @@
|
||||
<div class="admin-form padded">
|
||||
<div class="container is-max-widescreen">
|
||||
<form [formGroup]="form">
|
||||
<header class="columns">
|
||||
<div class="column">
|
||||
<h1 class="title is-2">
|
||||
{{ 'creation.title' | translate }}
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
<button class="btn is-success is-fixed-bottom" (click)="createPoll()" *ngIf="!environment.production">
|
||||
<i class="fa fa-save"></i>
|
||||
Enregistrer le sondage (sans vérifier)
|
||||
</button>
|
||||
<button class="btn btn--warning" (click)="askInitFormDefault()">
|
||||
<i class="fa fa-refresh"></i>
|
||||
Tout réinitialiser
|
||||
</button>
|
||||
<button class="btn is-default" (click)="automaticSlug()">
|
||||
<i class="fa fa-refresh"></i>
|
||||
Slug automatique
|
||||
</button>
|
||||
<main class="columns">
|
||||
<div class="column">
|
||||
<label class="label is-medium" for="kind">
|
||||
{{ 'creation.want' | translate }}
|
||||
</label>
|
||||
<!-- <div class="step-choices" *ngIf="currentStep === 'base'">-->
|
||||
<app-kind-select [form]="form"></app-kind-select>
|
||||
<app-base-config [form]="form"></app-base-config>
|
||||
<!-- </div>-->
|
||||
<!-- <div class="step-choices" *ngIf="currentStep === 'choices'"> </div>-->
|
||||
<app-date-select *ngIf="form.value && form.value.kind == 'date'" [form]="form"></app-date-select>
|
||||
<app-text-select *ngIf="form.value && form.value.kind == 'text'" [form]="form"></app-text-select>
|
||||
<div class="admin-form">
|
||||
<section class="min-height padded">
|
||||
<router-outlet>
|
||||
<app-step-one [form]="form"></app-step-one>
|
||||
</router-outlet>
|
||||
|
||||
<button
|
||||
class="btn"
|
||||
[class]="{ 'is-primary': advancedDisplayEnabled, 'is-info': !advancedDisplayEnabled }"
|
||||
(click)="advancedDisplayEnabled = !advancedDisplayEnabled"
|
||||
>
|
||||
<i class="fa fa-save"></i>
|
||||
{{ 'creation.advanced' | translate }}
|
||||
</button>
|
||||
<app-advanced-config
|
||||
[poll]="poll"
|
||||
[form]="form"
|
||||
*ngIf="advancedDisplayEnabled"
|
||||
></app-advanced-config>
|
||||
|
||||
<!-- <div class="bar-nav-admin">-->
|
||||
<!-- <div class="columns">-->
|
||||
<!-- <div class="column">-->
|
||||
<!-- <p class="control">-->
|
||||
<!-- <a class="button is-light" (click)="goPreviousStep()">-->
|
||||
<!-- Précédent-->
|
||||
<!-- </a>-->
|
||||
<!-- </p>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="column">-->
|
||||
<!-- <p class="control text-right">-->
|
||||
<!-- <a class="button is-primary" (click)="goNextStep()">-->
|
||||
<!-- Suivant-->
|
||||
<!-- </a>-->
|
||||
<!-- </p>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</main>
|
||||
<app-picker [form]="form" *ngIf="displayDatePicker"></app-picker>
|
||||
<app-errors-list [form]="form"></app-errors-list>
|
||||
<button
|
||||
[disabled]="!form.valid && form.touched"
|
||||
class="btn is-success is-fixed-bottom"
|
||||
(click)="createPoll()"
|
||||
>
|
||||
<i class="fa fa-save"></i>
|
||||
Enregistrer le sondage
|
||||
</button>
|
||||
<button class="btn is-success is-fixed-bottom" (click)="createPoll()" *ngIf="!environment.production">
|
||||
<i class="fa fa-save"></i>
|
||||
Enregistrer le sondage (sans vérifier)
|
||||
</button>
|
||||
|
||||
<footer class="column" *ngIf="show_debug_data">
|
||||
<h2>Debug data</h2>
|
||||
<pre class="debug padded warning">
|
||||
form values :
|
||||
{{ form.value | json }}
|
||||
</pre
|
||||
>
|
||||
<pre class="debug padded warning">
|
||||
poll initial values :
|
||||
{{ poll | json }}
|
||||
</pre
|
||||
>
|
||||
</footer>
|
||||
<hr />
|
||||
</form>
|
||||
</div>
|
||||
<app-errors-list [form]="pollService.form"></app-errors-list>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -0,0 +1,10 @@
|
||||
@import '../../../../styles/variables';
|
||||
.admin-form {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
textarea {
|
||||
border: solid 1px $border-color;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
@ -1,231 +1,40 @@
|
||||
import { ChangeDetectorRef, Component, Inject, Input, OnInit, AfterViewInit } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { Poll } from '../../../core/models/poll.model';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { UuidService } from '../../../core/services/uuid.service';
|
||||
import { ApiService } from '../../../core/services/api.service';
|
||||
import { ToastService } from '../../../core/services/toast.service';
|
||||
import { PollService } from '../../../core/services/poll.service';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Router } from '@angular/router';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { PollUtilitiesService } from '../../../core/services/poll.utilities.service';
|
||||
import { StorageService } from '../../../core/services/storage.service';
|
||||
import { DateUtilitiesService } from '../../../core/services/date.utilities.service';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-form',
|
||||
templateUrl: './form.component.html',
|
||||
styleUrls: ['./form.component.scss'],
|
||||
})
|
||||
export class FormComponent implements OnInit, AfterViewInit {
|
||||
export class FormComponent implements OnInit {
|
||||
@Input()
|
||||
public poll?: Poll;
|
||||
public form: FormGroup;
|
||||
|
||||
public displayDatePicker = false;
|
||||
public advancedDisplayEnabled = false;
|
||||
public show_debug_data = false;
|
||||
public currentStep = 'base';
|
||||
public steps = ['base', 'choices', 'advanced'];
|
||||
|
||||
public environment = environment;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private cd: ChangeDetectorRef,
|
||||
private pollUtilitiesService: PollUtilitiesService,
|
||||
private uuidService: UuidService,
|
||||
private toastService: ToastService,
|
||||
private pollService: PollService,
|
||||
private storageService: StorageService,
|
||||
public apiService: ApiService,
|
||||
public dateUtils: DateUtilitiesService,
|
||||
public pollService: PollService,
|
||||
private router: Router,
|
||||
private utilitiesService: PollUtilitiesService,
|
||||
public route: ActivatedRoute,
|
||||
private apiService: ApiService,
|
||||
@Inject(DOCUMENT) private document: any
|
||||
) {}
|
||||
) {
|
||||
this.form = this.pollService.form;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initFormDefault();
|
||||
// this.goNextStep();
|
||||
this.pollService.askInitFormDefault();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
// focus on first field of the creation form
|
||||
const firstField = this.document.querySelector('#kind');
|
||||
if (firstField) {
|
||||
console.log('focus on ', firstField);
|
||||
firstField.focus();
|
||||
} else {
|
||||
console.log('no first field of form');
|
||||
}
|
||||
}
|
||||
|
||||
initFormDefault(showDemoValues = environment.autofill): void {
|
||||
const creationDate = new Date();
|
||||
|
||||
// choices of date are managed outside of this form
|
||||
this.form = this.fb.group({
|
||||
title: ['', [Validators.required, Validators.minLength(5)]],
|
||||
creatorPseudo: ['', [Validators.required]],
|
||||
creatorEmail: ['', [Validators.required, Validators.email]],
|
||||
custom_url: [this.pollUtilitiesService.makeUuid(), [Validators.required]],
|
||||
description: ['', [Validators.required]],
|
||||
kind: ['date', [Validators.required]],
|
||||
areResultsPublic: [true, [Validators.required]],
|
||||
whoCanChangeAnswers: ['everybody', [Validators.required]],
|
||||
isProtectedByPassword: [false, [Validators.required]],
|
||||
allowNewDateTime: [false, [Validators.required]],
|
||||
isOwnerNotifiedByEmailOnNewVote: [false, [Validators.required]],
|
||||
isOwnerNotifiedByEmailOnNewComment: [false, [Validators.required]],
|
||||
isYesAnswerAvailable: [false, [Validators.required]],
|
||||
isMaybeAnswerAvailable: [false, [Validators.required]],
|
||||
isNoAnswerAvailable: [false, [Validators.required]],
|
||||
isAboutDate: [true, [Validators.required]],
|
||||
isZeroKnoledge: [false, [Validators.required]],
|
||||
useVoterUniqueLink: [false, [Validators.required]],
|
||||
expiresDaysDelay: [60, [Validators.required, Validators.min(1), Validators.max(365)]],
|
||||
maxCountOfAnswers: [150, [Validators.required, Validators.min(1), Validators.max(5000)]],
|
||||
allowComments: [true, [Validators.required]],
|
||||
password: ['', []],
|
||||
voterEmailList: ['', []],
|
||||
natural_lang_interval: ['', []],
|
||||
dateCreated: [creationDate, [Validators.required]],
|
||||
hasSeveralHours: [false, [Validators.required]],
|
||||
hasMaxCountOfAnswers: [true, [Validators.required, Validators.min(1)]],
|
||||
startDateInterval: ['', [Validators.required]],
|
||||
endDateInterval: ['', [Validators.required]],
|
||||
});
|
||||
|
||||
// take back values from pollservice
|
||||
// this.form.patchValue(this.pollService.poll);
|
||||
this.setDefaultFormValues();
|
||||
|
||||
if (showDemoValues) {
|
||||
this.setDemoValues();
|
||||
this.toastService.display('default values filled for demo');
|
||||
}
|
||||
|
||||
if (environment.autoSendNewPoll) {
|
||||
this.createPoll();
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultFormValues(): void {
|
||||
this.form.patchValue({
|
||||
creatorPseudo: 'Anne Onyme',
|
||||
creatorEmail: 'anne_onyme@anonymous_email.com',
|
||||
description: 'RSVP',
|
||||
isAboutDate: true,
|
||||
hasSeveralHours: false,
|
||||
kind: 'date',
|
||||
password: '',
|
||||
whoCanChangeAnswers: 'everybody',
|
||||
isProtectedByPassword: false,
|
||||
isOwnerNotifiedByEmailOnNewVote: false,
|
||||
isOwnerNotifiedByEmailOnNewComment: false,
|
||||
isYesAnswerAvailable: true,
|
||||
isMaybeAnswerAvailable: false,
|
||||
isNoAnswerAvailable: false,
|
||||
isZeroKnoledge: true,
|
||||
areResultsPublic: true,
|
||||
allowComments: true,
|
||||
expiresDaysDelay: environment.expiresDaysDelay,
|
||||
maxCountOfAnswers: environment.maxCountOfAnswers,
|
||||
allowNewDateTime: false,
|
||||
// startDateInterval: formatDate(new Date(), 'yyyy-MM-dd', 'fr_FR'),
|
||||
endDateInterval: formatDate(
|
||||
this.dateUtils.addDaysToDate(environment.interval_days_default, new Date()),
|
||||
'yyyy-MM-dd',
|
||||
'fr_FR'
|
||||
),
|
||||
});
|
||||
console.log("this.form.controls['startDateInterval']", this.form.controls['startDateInterval']);
|
||||
this.form.controls['startDateInterval'].setValue(formatDate(new Date(), 'yyyy-MM-dd', 'fr_FR'));
|
||||
console.log("this.form.controls['startDateInterval']", this.form.controls['startDateInterval']);
|
||||
this.automaticSlug();
|
||||
}
|
||||
|
||||
/**
|
||||
* add example values to the form, overrides defaults of PollConfiguration
|
||||
*/
|
||||
setDemoValues(): void {
|
||||
const title = 'le titre de démo __ ' + new Date().getTime();
|
||||
|
||||
this.form.patchValue({ creatorPseudo: 'Chuck Norris', creatorEmail: 'chucknorris@example.com' });
|
||||
|
||||
this.form.patchValue({
|
||||
title: title,
|
||||
custom_url: this.pollUtilitiesService.makeSlugFromString(title),
|
||||
description: 'répondez SVP <3 ! *-*',
|
||||
creatorPseudo: 'Chuck Norris',
|
||||
creatorEmail: 'chucknorris@example.com',
|
||||
});
|
||||
}
|
||||
|
||||
askInitFormDefault(): void {
|
||||
this.toastService.display('formulaire réinitialisé', 'info');
|
||||
}
|
||||
|
||||
/**
|
||||
* set the poll custom_url from other data of the poll
|
||||
*/
|
||||
automaticSlug(): void {
|
||||
this.form.patchValue({
|
||||
custom_url:
|
||||
this.pollService.convertTextToSlug(this.form.value.title) +
|
||||
'_' +
|
||||
this.utilitiesService.makeUuid().substr(0, 12),
|
||||
});
|
||||
}
|
||||
|
||||
goPreviousStep() {
|
||||
alert('todo');
|
||||
}
|
||||
|
||||
goNextStep() {
|
||||
let indexCurrentStep = this.steps.indexOf(this.currentStep);
|
||||
indexCurrentStep += 1;
|
||||
this.currentStep = this.steps[indexCurrentStep];
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
public createPoll(): void {
|
||||
const newpoll = this.pollService.newPollFromForm(this.form);
|
||||
console.log('newpoll', newpoll);
|
||||
const router = this.router;
|
||||
|
||||
if (!environment.production) {
|
||||
this.toastService.display('mode dev : envoi du form sans validation');
|
||||
this.apiService.createPoll(newpoll).then(
|
||||
(resp: any) => {
|
||||
this.pollService.updateCurrentPoll(resp.data.poll);
|
||||
this.storageService.userPolls.push(resp.data.poll);
|
||||
this.storageService.vote_stack.owner.polls.push(resp.data.poll);
|
||||
this.toastService.display('sauvegarde du nouveau sondage réussie');
|
||||
router.navigate(['success']);
|
||||
},
|
||||
(err) => {
|
||||
this.toastService.display('erreur lors de la sauvegarde ' + err.message);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
if (this.form.valid) {
|
||||
this.toastService.display("C'est parti!");
|
||||
this.apiService.createPoll(newpoll).then(
|
||||
(resp: any) => {
|
||||
this.pollService.updateCurrentPoll(resp.data.poll);
|
||||
this.storageService.userPolls.push(resp.data.poll);
|
||||
this.storageService.vote_stack.owner.polls.push(resp.data.poll);
|
||||
this.toastService.display('sauvegarde du nouveau sondage réussie');
|
||||
router.navigate(['success']);
|
||||
},
|
||||
(err) => {
|
||||
this.toastService.display('erreur lors de la sauvegarde');
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.toastService.display('invalid form');
|
||||
}
|
||||
}
|
||||
}
|
||||
goNextStep() {}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
<app-stepper [step_current]="5" [step_max]="5"></app-stepper>
|
||||
<app-errors-list [form]="pollService.form"></app-errors-list>
|
||||
<app-success [poll]="pollService.form.value"></app-success>
|
||||
|
||||
<section class="supplement container">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/1']">
|
||||
<i class="fa fa-pencil"></i>
|
||||
modifier le sondage
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn--warning" (click)="askInitFormDefault()">
|
||||
<i class="fa fa-refresh"></i>
|
||||
Tout réinitialiser
|
||||
</button>
|
||||
|
||||
<div class="well">
|
||||
{{ pollService.form.value.custom_url }}
|
||||
</div>
|
||||
<div class="has-background-danger" *ngIf="!pollService.form.valid">
|
||||
le formulaire est invalide
|
||||
<pre> {{ pollService.form.errors | json }}</pre>
|
||||
</div>
|
||||
</section>
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StepFiveComponent } from './step-five.component';
|
||||
|
||||
describe('StepFiveComponent', () => {
|
||||
let component: StepFiveComponent;
|
||||
let fixture: ComponentFixture<StepFiveComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StepFiveComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StepFiveComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,27 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { PollService } from '../../../../../core/services/poll.service';
|
||||
import { ApiService } from '../../../../../core/services/api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-step-five',
|
||||
templateUrl: './step-five.component.html',
|
||||
styleUrls: ['./step-five.component.scss'],
|
||||
})
|
||||
export class StepFiveComponent implements OnInit {
|
||||
@Input() step_max: any;
|
||||
@Input() public form: FormGroup;
|
||||
poll: any;
|
||||
constructor(public pollService: PollService) {
|
||||
this.pollService.step_current = 5;
|
||||
}
|
||||
ngOnInit(): void {}
|
||||
|
||||
askInitFormDefault() {
|
||||
if (window.confirm('réinitialiser le formulaire ?')) {
|
||||
this.pollService.askInitFormDefault();
|
||||
}
|
||||
}
|
||||
|
||||
automaticSlug() {}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
<div class="step">
|
||||
<div class="min-height">
|
||||
<form action="#" [formGroup]="pollService.form">
|
||||
<app-stepper [step_current]="4" [step_max]="pollService.step_max"></app-stepper>
|
||||
<app-errors-list [form]="pollService.form"></app-errors-list>
|
||||
<div class="creator-infos">
|
||||
<label class="" for="creatorEmail">
|
||||
<span>
|
||||
{{ 'creation.name' | translate }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
#title
|
||||
matInput
|
||||
placeholder="pseudo"
|
||||
formControlName="creatorPseudo"
|
||||
id="creatorPseudo"
|
||||
required
|
||||
/>
|
||||
<label class="hidden" for="creatorPseudo">
|
||||
<span>
|
||||
{{ 'creation.email' | translate }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
#title
|
||||
matInput
|
||||
placeholder="mon-email@example.com"
|
||||
formControlName="creatorEmail"
|
||||
id="creatorEmail"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<fieldset class="advanced-config">
|
||||
<button
|
||||
class="button is-unchecked-info"
|
||||
[ngClass]="{ 'is-info': !advancedDisplayEnabled, 'is-primary': advancedDisplayEnabled }"
|
||||
(click)="advancedDisplayEnabled = !advancedDisplayEnabled"
|
||||
>
|
||||
<i class="fa fa-chevron-circle-down" *ngIf="!advancedDisplayEnabled"></i>
|
||||
<i class="fa fa-chevron-circle-up" *ngIf="advancedDisplayEnabled"></i>
|
||||
{{ 'creation.advanced' | translate }}
|
||||
</button>
|
||||
<fieldset class="complete well" *ngIf="advancedDisplayEnabled">
|
||||
<app-advanced-config [form]="pollService.form"></app-advanced-config>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<button class="button is-secondary is-fullwidth" [routerLink]="['/administration/step/3']">
|
||||
précédent
|
||||
</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<button class="btn is-primary is-fullwidth" (click)="createPoll()" [disabled]="!pollService.form.valid">
|
||||
<i class="fa fa-save"></i>
|
||||
Enregistrer le sondage
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1 @@
|
||||
@import '../../../../../../styles/variables';
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StepFourComponent } from './step-four.component';
|
||||
|
||||
describe('StepFourComponent', () => {
|
||||
let component: StepFourComponent;
|
||||
let fixture: ComponentFixture<StepFourComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StepFourComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StepFourComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,35 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { PollService } from '../../../../../core/services/poll.service';
|
||||
import { environment } from '../../../../../../environments/environment';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-step-four',
|
||||
templateUrl: './step-four.component.html',
|
||||
styleUrls: ['./step-four.component.scss'],
|
||||
})
|
||||
export class StepFourComponent implements OnInit {
|
||||
urlPrefix: any;
|
||||
advancedDisplayEnabled: boolean = environment.advanced_options_display;
|
||||
@Input()
|
||||
step_max: any;
|
||||
@Input()
|
||||
form: any;
|
||||
|
||||
constructor(private router: Router, public pollService: PollService) {
|
||||
this.pollService.step_current = 4;
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
createPoll() {
|
||||
this.pollService.createPoll().then(
|
||||
(resp) => {
|
||||
this.router.navigate(['administration/success']);
|
||||
},
|
||||
(err) => {
|
||||
console.error('oops err', err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
<div class="step step-container">
|
||||
<form class="min-height" [formGroup]="pollService.form">
|
||||
<app-stepper [step_current]="1" [step_max]="5"></app-stepper>
|
||||
<section class="poll-title">
|
||||
<h2 class="title is-2">
|
||||
{{ 'creation.choose_title' | translate }}
|
||||
</h2>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div>
|
||||
<label for="title">{{ 'creation.choose_title_label' | translate }}</label>
|
||||
</div>
|
||||
<input
|
||||
class="input is-fullwidth"
|
||||
#title
|
||||
[placeholder]="'creation.choose_title_placeholder' | translate"
|
||||
formControlName="title"
|
||||
(keyup)="pollService.updateSlug()"
|
||||
(blur)="pollService.updateSlug()"
|
||||
id="title"
|
||||
maxlength="140"
|
||||
autofocus="autofocus"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="poll-description">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<label for="descr">Description (optionnel)</label>
|
||||
<!-- <div class="rich-text-toggle">-->
|
||||
<!-- <label for="richTextMode">mode de saisie avancée</label>-->
|
||||
|
||||
<!-- <mat-checkbox formControlName="richTextMode" id="richTextMode"></mat-checkbox>-->
|
||||
<!-- </div>-->
|
||||
<div class="rich-toolbar" *ngIf="pollService.form.value.richTextMode">
|
||||
richTextMode activé
|
||||
</div>
|
||||
<textarea
|
||||
class="ui-inputtextarea is-fullwidth is-block"
|
||||
#description
|
||||
matInput
|
||||
id="descr"
|
||||
class="is-large is-full input"
|
||||
placeholder="Description"
|
||||
formControlName="description"
|
||||
required
|
||||
maxlength="300"
|
||||
></textarea>
|
||||
<div
|
||||
class="text-info padded"
|
||||
[ngClass]="{ 'has-background-warning': pollService.form.value.description.length === 300 }"
|
||||
>
|
||||
{{ pollService.form.value.description.length }} / 300 caractères maximum
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<button class="button is-warning is-fullwidth" [routerLink]="['/']">
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<!-- [disabled]="form.invalid"-->
|
||||
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/2']">
|
||||
Suivant
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StepOneComponent } from './step-one.component';
|
||||
|
||||
describe('StepOneComponent', () => {
|
||||
let component: StepOneComponent;
|
||||
let fixture: ComponentFixture<StepOneComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StepOneComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StepOneComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,27 @@
|
||||
import { Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { PollService } from '../../../../../core/services/poll.service';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-step-one',
|
||||
templateUrl: './step-one.component.html',
|
||||
styleUrls: ['./step-one.component.scss'],
|
||||
})
|
||||
export class StepOneComponent implements OnInit {
|
||||
constructor(public pollService: PollService, @Inject(DOCUMENT) private document: any) {}
|
||||
|
||||
@Input()
|
||||
step_max: any;
|
||||
@Input()
|
||||
form: FormGroup;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pollService.step_current = 1;
|
||||
const selector = '#title';
|
||||
const firstField = this.document.querySelector(selector);
|
||||
if (firstField) {
|
||||
firstField.focus();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<div class="step min-height">
|
||||
<app-stepper [step_current]="3" [step_max]="5"></app-stepper>
|
||||
<app-errors-list [form]="pollService.form"></app-errors-list>
|
||||
<!-- choix spécialement pour les dates-->
|
||||
<span class="count-dates title">
|
||||
{{ pollService.calendar.length }}
|
||||
</span>
|
||||
<span> - {{ 'dates.count_dates' | translate }} </span>
|
||||
|
||||
<div class="calendar" *ngIf="mode_calendar">
|
||||
<p-calendar
|
||||
[(ngModel)]="pollService.calendar"
|
||||
firstDayOfWeek="1"
|
||||
selectionMode="multiple"
|
||||
inputId="multiple"
|
||||
showButtonBar="true"
|
||||
[locale]="'calendar_widget' | translate"
|
||||
[disabledDates]="pollService.disabled_dates"
|
||||
[inline]="true"
|
||||
[showWeek]="false"
|
||||
></p-calendar>
|
||||
</div>
|
||||
<button class="button" (click)="mode_calendar = !mode_calendar" [ngClass]="{ 'is-primary': !mode_calendar }">
|
||||
Saisir les dates manuellement
|
||||
</button>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="dates-list">
|
||||
<div class="actions">
|
||||
<button
|
||||
(click)="pollService.addTime()"
|
||||
*ngIf="false == pollService.allowSeveralHours"
|
||||
class="button is-primary is-block is-fullwidth"
|
||||
id="add_time_button"
|
||||
>
|
||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||
{{ 'dates.add_time' | translate }}
|
||||
</button>
|
||||
<button class="button" (click)="pollService.allowSeveralHours = !pollService.allowSeveralHours">
|
||||
Horaires différentes pour chaque jour
|
||||
</button>
|
||||
<button
|
||||
(click)="pollService.removeAllTimes()"
|
||||
*ngIf="pollService.timeList.length && false == pollService.allowSeveralHours"
|
||||
class="btn is-warning marged"
|
||||
id="remove_time_button"
|
||||
>
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
Aucune plage horaire
|
||||
</button>
|
||||
<button
|
||||
(click)="pollService.resetTimes()"
|
||||
*ngIf="pollService.timeList.length && false == pollService.allowSeveralHours"
|
||||
class="btn is-warning marged"
|
||||
id="reset_time_button"
|
||||
>
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
réinitialiser
|
||||
</button>
|
||||
</div>
|
||||
<div class="title" *ngIf="pollService.timeList.length">
|
||||
<span class="count-dates">
|
||||
{{ pollService.timeList.length }}
|
||||
</span>
|
||||
<span class="count-dates-txt">
|
||||
{{ 'dates.count_time' | translate }}
|
||||
(pour chaque jour)
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="pollService.timeList.length && false == pollService.allowSeveralHours"
|
||||
class="marged padded identical-dates"
|
||||
>
|
||||
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
|
||||
<div *ngFor="let time of pollService.timeList; index as id" class="time-choice" cdkDrag>
|
||||
<label for="timeChoices_{{ id }}">
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i>
|
||||
</label>
|
||||
<input
|
||||
[(ngModel)]="time.literal"
|
||||
name="timeChoices_{{ id }}"
|
||||
type="text"
|
||||
id="timeChoices_{{ id }}"
|
||||
/>
|
||||
<button (click)="time.timeList.splice(id, 1)" class="btn btn-warning">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<button class="button is-secondary is-fullwidth" [routerLink]="['/administration/step/2']">
|
||||
précédent
|
||||
</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<!-- [disabled]="form.invalid"-->
|
||||
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/4']">
|
||||
suivant
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,9 @@
|
||||
@import '../../../../../../styles/variables';
|
||||
|
||||
.ui-datepicker table td.ui-datepicker-today > a.ui-state-active,
|
||||
.ui-datepicker table td.ui-datepicker-today > span.ui-state-active {
|
||||
background-color: $primary-color !important;
|
||||
}
|
||||
.calendar {
|
||||
margin-top: 1em;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StepThreeComponent } from './step-three.component';
|
||||
|
||||
describe('StepThreeComponent', () => {
|
||||
let component: StepThreeComponent;
|
||||
let fixture: ComponentFixture<StepThreeComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StepThreeComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StepThreeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { PollService } from '../../../../../core/services/poll.service';
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
|
||||
@Component({
|
||||
selector: 'app-step-three',
|
||||
templateUrl: './step-three.component.html',
|
||||
styleUrls: ['./step-three.component.scss'],
|
||||
})
|
||||
export class StepThreeComponent implements OnInit {
|
||||
@Input()
|
||||
step_max: any;
|
||||
@Input()
|
||||
form: any;
|
||||
public mode_calendar = true;
|
||||
|
||||
constructor(public pollService: PollService) {
|
||||
this.pollService.step_current = 3;
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
drop(event: CdkDragDrop<string[]>) {
|
||||
// moveItemInArray(this.pollService.choices, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<div class="step step-container form-field poll-kind">
|
||||
<div class="min-height">
|
||||
<app-stepper [step_current]="2" [step_max]="5"></app-stepper>
|
||||
<app-errors-list [form]="pollService.form"></app-errors-list>
|
||||
<h2 class="title is-2">
|
||||
{{ 'creation.want' | translate }}
|
||||
</h2>
|
||||
<div class="container">
|
||||
<div class="kind-of-poll columns">
|
||||
<div class="column">
|
||||
<button
|
||||
class="button is-fullwidth"
|
||||
[ngClass]="{ 'is-selected is-primary': pollService.form.controls.isAboutDate.value }"
|
||||
(click)="pollService.form.controls.isAboutDate.setValue(true)"
|
||||
>
|
||||
<i class="fa fa-calendar"></i>
|
||||
{{ 'creation.kind.date' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<button
|
||||
class="button is-fullwidth"
|
||||
[ngClass]="{ 'is-selected is-primary': !pollService.form.controls.isAboutDate.value }"
|
||||
(click)="pollService.form.controls.isAboutDate.setValue(false)"
|
||||
>
|
||||
<i class="fa fa-list-ul"></i>
|
||||
{{ 'creation.kind.classic' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<button class="button is-secondary is-fullwidth" [routerLink]="['/administration/step/1']">
|
||||
précédent
|
||||
</button>
|
||||
</div>
|
||||
<div class="column">
|
||||
<!-- [disabled]="form.invalid"-->
|
||||
<button class="button is-primary is-fullwidth" [routerLink]="['/administration/step/3']">
|
||||
suivant
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,16 @@
|
||||
@import '../../../../../../styles/variables';
|
||||
|
||||
.kind-of-poll {
|
||||
margin-top: 5em;
|
||||
.fa {
|
||||
margin-right: 1em;
|
||||
}
|
||||
.button {
|
||||
background: $d-grey;
|
||||
border: solid white 1px;
|
||||
&.is-selected {
|
||||
border: solid $primary-color 1px;
|
||||
color: $font_color;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StepTwoComponent } from './step-two.component';
|
||||
|
||||
describe('StepTwoComponent', () => {
|
||||
let component: StepTwoComponent;
|
||||
let fixture: ComponentFixture<StepTwoComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [StepTwoComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StepTwoComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,62 @@
|
||||
import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { FormArray, FormBuilder } from '@angular/forms';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
||||
import { Router } from '@angular/router';
|
||||
import { UuidService } from '../../../../../core/services/uuid.service';
|
||||
import { ToastService } from '../../../../../core/services/toast.service';
|
||||
import { PollService } from '../../../../../core/services/poll.service';
|
||||
import { DateUtilitiesService } from '../../../../../core/services/date.utilities.service';
|
||||
import { ApiService } from '../../../../../core/services/api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-step-two',
|
||||
templateUrl: './step-two.component.html',
|
||||
styleUrls: ['./step-two.component.scss'],
|
||||
})
|
||||
export class StepTwoComponent implements OnInit {
|
||||
ngOnInit(): void {}
|
||||
|
||||
@Input()
|
||||
form: any;
|
||||
@Input()
|
||||
step_max: any;
|
||||
timeList: any;
|
||||
allowSeveralHours: string;
|
||||
dateList: any;
|
||||
showDateInterval: boolean;
|
||||
intervalDays: any;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private cd: ChangeDetectorRef,
|
||||
private uuidService: UuidService,
|
||||
private toastService: ToastService,
|
||||
public pollService: PollService,
|
||||
private router: Router,
|
||||
public dateUtilities: DateUtilitiesService,
|
||||
private apiService: ApiService,
|
||||
@Inject(DOCUMENT) private document: any
|
||||
) {
|
||||
this.form = this.pollService.form;
|
||||
this.pollService.step_current = 2;
|
||||
}
|
||||
|
||||
addIntervalOfDates() {}
|
||||
|
||||
get choices(): FormArray {
|
||||
return this.form.get('choices') as FormArray;
|
||||
}
|
||||
|
||||
addTime() {}
|
||||
|
||||
removeAllTimes() {}
|
||||
|
||||
resetTimes() {}
|
||||
|
||||
addChoice() {}
|
||||
|
||||
addTimeToDate(choice: any, id: number) {}
|
||||
|
||||
countDays() {}
|
||||
}
|
@ -1,114 +1,55 @@
|
||||
<mat-vertical-stepper #stepper linear>
|
||||
<mat-step [stepControl]="pollFormGroup" class="is-expanded">
|
||||
<form [formGroup]="pollFormGroup">
|
||||
<ng-template matStepLabel>Informations du sondage</ng-template>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Titre</mat-label>
|
||||
<input #title matInput placeholder="Question posée, sujet" formControlName="title" required />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="is-flex">
|
||||
<mat-label>Description</mat-label>
|
||||
<textarea
|
||||
#description
|
||||
matInput
|
||||
placeholder="Description"
|
||||
formControlName="description"
|
||||
required
|
||||
></textarea>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="description.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="description.value = ''"
|
||||
<section class="creation-stepper">
|
||||
<div class="shortcuts">
|
||||
<a
|
||||
class="shortcut"
|
||||
href="#"
|
||||
[routerLink]="['/administration/step/1']"
|
||||
[ngClass]="{ 'is-active': pollService.step_current == 1 }"
|
||||
>1</a
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="is-flex">
|
||||
<mat-label>Url pour les participants</mat-label>
|
||||
<span matPrefix>{{ urlPrefix }}</span>
|
||||
<input #slug matInput placeholder="Url" formControlName="slug" required />
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="slug.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="slug.value = ''"
|
||||
<a
|
||||
class="shortcut"
|
||||
href="#"
|
||||
[routerLink]="['/administration/step/2']"
|
||||
[ngClass]="{ 'is-active': pollService.step_current == 2 }"
|
||||
>2</a
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<div>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="configurationFormGroup">
|
||||
<form [formGroup]="configurationFormGroup">
|
||||
<ng-template matStepLabel>PollConfiguration du sondage</ng-template>
|
||||
<mat-form-field appearance="outline" class="is-flex">
|
||||
<mat-label>Nombre de jours avant expiration</mat-label>
|
||||
<input
|
||||
#expiracy
|
||||
matInput
|
||||
type="number"
|
||||
placeholder="Nombre de jours avant expiration"
|
||||
formControlName="expiracyNumberOfDays"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="expiracy.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="expiracy.value = ''"
|
||||
<a
|
||||
class="shortcut"
|
||||
href="#"
|
||||
[routerLink]="['/administration/step/3']"
|
||||
[ngClass]="{ 'is-active': pollService.step_current == 3 }"
|
||||
>3</a
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<mat-checkbox class="is-flex" formControlName="areResultsPublic">
|
||||
Les participants pourront consulter les résultats
|
||||
</mat-checkbox>
|
||||
<mat-checkbox class="is-flex" formControlName="isAboutDate">
|
||||
Les choix possibles concerneront des dates
|
||||
</mat-checkbox>
|
||||
<mat-checkbox class="is-flex" formControlName="isProtectedByPassword">
|
||||
Le sondage sera protégé par un mot de passe
|
||||
</mat-checkbox>
|
||||
<mat-checkbox class="is-flex" formControlName="isOwnerNotifiedByEmailOnNewVote">
|
||||
Vous recevrez un mail à chaque nouvelle participation
|
||||
</mat-checkbox>
|
||||
<mat-checkbox class="is-flex" formControlName="isOwnerNotifiedByEmailOnNewComment">
|
||||
Vous recevrez un mail à chaque nouveau commentaire
|
||||
</mat-checkbox>
|
||||
<mat-checkbox class="is-flex" formControlName="isMaybeAnswerAvailable">
|
||||
La réponse « peut-être » sera disponible
|
||||
</mat-checkbox>
|
||||
|
||||
<div>
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button matStepperNext>Next</button>
|
||||
<a
|
||||
class="shortcut"
|
||||
href="#"
|
||||
[routerLink]="['/administration/step/4']"
|
||||
[ngClass]="{ 'is-active': pollService.step_current == 4 }"
|
||||
>4</a
|
||||
>
|
||||
<a
|
||||
class="shortcut"
|
||||
href="#"
|
||||
[routerLink]="['/administration/step/5']"
|
||||
[ngClass]="{ 'is-active': pollService.step_current == 5 }"
|
||||
>5</a
|
||||
>
|
||||
<!-- <a class="shortcut" href="#" [routerLink]="['/administration/step/6']" [ngClass]="{'is-active':pollService.step_current == 6}">6</a>-->
|
||||
<!-- <a class="shortcut" href="#" [routerLink]="['/administration/step/7']" [ngClass]="{'is-active':pollService.step_current == 7}">7</a>-->
|
||||
</div>
|
||||
</form>
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>Done</ng-template>
|
||||
<p>You are now done.</p>
|
||||
<div>
|
||||
<button mat-button matStepperPrevious>Back</button>
|
||||
<button mat-button (click)="stepper.reset()">Reset</button>
|
||||
<div class="step-info">
|
||||
<h2 classs="title is-2" *ngIf="pollService.step_current == 1">
|
||||
{{ 'creation.title' | translate }}
|
||||
</h2>
|
||||
<h2 class="title is-3" *ngIf="pollService.step_current > 1">
|
||||
<span class="poll-title">
|
||||
{{ pollService.form.value.title }}
|
||||
</span>
|
||||
</h2>
|
||||
<h3 class="title is-2">Étape {{ step_current }} sur {{ step_max }}</h3>
|
||||
</div>
|
||||
<div>
|
||||
<button mat-button (click)="savePoll()" [disabled]="!pollFormGroup.valid || !configurationFormGroup.valid">
|
||||
Enregistrer le sondage
|
||||
</button>
|
||||
<div class="step-bar-container" style="width: 100%;">
|
||||
<div class="step-bar-progress" [ngStyle]="{ width: (step_current / step_max) * 100 + '%' }"></div>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-vertical-stepper>
|
||||
</section>
|
||||
|
@ -0,0 +1,35 @@
|
||||
@import '../../../../styles/variables';
|
||||
|
||||
.step-bar-container {
|
||||
margin: 1em 0;
|
||||
height: 0.5em;
|
||||
display: inline-block;
|
||||
min-width: 1px;
|
||||
background: $border-color !important;
|
||||
width: 100%;
|
||||
}
|
||||
.step-bar-progress {
|
||||
position: relative;
|
||||
top: -0.6em;
|
||||
left: 0;
|
||||
height: 0.5em;
|
||||
display: inline-block;
|
||||
min-width: 1px;
|
||||
background: $primary_color;
|
||||
}
|
||||
.shortcut {
|
||||
background: $dark-lavender;
|
||||
color: white;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
display: inline-block;
|
||||
border-radius: 100%;
|
||||
text-align: center;
|
||||
width: 4em;
|
||||
&.is-active {
|
||||
background: $font_color;
|
||||
}
|
||||
}
|
||||
.poll-title {
|
||||
color: $d-neutral;
|
||||
}
|
@ -1,55 +1,17 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
|
||||
import { Poll } from '../../../core/models/poll.model';
|
||||
import { UuidService } from '../../../core/services/uuid.service';
|
||||
import { DateService } from '../../../core/services/date.service';
|
||||
import { PollService } from '../../../core/services/poll.service';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-stepper',
|
||||
templateUrl: './stepper.component.html',
|
||||
styleUrls: ['./stepper.component.scss'],
|
||||
})
|
||||
export class StepperComponent implements OnInit {
|
||||
export class StepperComponent {
|
||||
@Input()
|
||||
public poll?: Poll;
|
||||
|
||||
public pollFormGroup: FormGroup;
|
||||
public configurationFormGroup: FormGroup;
|
||||
public choicesFormGroup: FormGroup;
|
||||
|
||||
public urlPrefix = '/participation/';
|
||||
|
||||
constructor(private fb: FormBuilder, private uuidService: UuidService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pollFormGroup = this.fb.group({
|
||||
question: [this.poll ? this.poll.title : '', [Validators.required]],
|
||||
slug: [this.poll ? this.poll.custom_url : this.uuidService.getUUID(), [Validators.required]],
|
||||
description: [this.poll ? this.poll.description : ''],
|
||||
});
|
||||
|
||||
this.configurationFormGroup = this.fb.group({
|
||||
title: [this.poll ? this.poll : false, [Validators.required]],
|
||||
isAboutDate: [this.poll ? this.poll.kind === 'date' : false, [Validators.required]],
|
||||
isProtectedByPassword: [this.poll ? this.poll.password.length : false, [Validators.required]],
|
||||
isOwnerNotifiedByEmailOnNewVote: [
|
||||
this.poll ? this.poll.isOwnerNotifiedByEmailOnNewVote : false,
|
||||
[Validators.required],
|
||||
],
|
||||
isOwnerNotifiedByEmailOnNewComment: [
|
||||
this.poll ? this.poll.isOwnerNotifiedByEmailOnNewComment : false,
|
||||
[Validators.required],
|
||||
],
|
||||
areResultsPublic: [this.poll ? this.poll.areResultsPublic : true, [Validators.required]],
|
||||
expiracyNumberOfDays: [this.poll ? this.poll.default_expiracy_days_from_now : '60', [Validators.required]],
|
||||
});
|
||||
}
|
||||
|
||||
public savePoll(): void {
|
||||
if (this.pollFormGroup.valid && this.configurationFormGroup.valid) {
|
||||
console.log('Le sondage est correctement rempli, prêt à enregistrer.');
|
||||
// TODO : save the poll
|
||||
}
|
||||
}
|
||||
public step_current: number = 1;
|
||||
@Input()
|
||||
public step_max: number = 5;
|
||||
public show_shortcuts = environment.showStepperShortcuts;
|
||||
constructor(public pollService: PollService) {}
|
||||
}
|
||||
|
@ -1,89 +1,108 @@
|
||||
<section class="hero is-medium is-success">
|
||||
<section
|
||||
class="hero is-medium"
|
||||
[ngClass]="{ 'has-background-success': pollService.admin_key, 'has-background-danger': pollService.admin_key }"
|
||||
>
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<div class="main-block">
|
||||
<h1 class="title is-1">🎉 {{ 'resume.title' | translate }}</h1>
|
||||
<h1 class="title is-1" *ngIf="pollService.admin_key">🎉 {{ 'resume.title' | translate }}</h1>
|
||||
<h2 class="subtitle">
|
||||
Votre sondage «
|
||||
Votre sondage
|
||||
<br />
|
||||
«
|
||||
<strong class="poll-title">
|
||||
{{ poll.title }}
|
||||
{{ pollService.form.value.title }}
|
||||
</strong>
|
||||
» a bien été créé !
|
||||
»
|
||||
<span *ngIf="!pollService.admin_key">
|
||||
n'a pas été créé :(
|
||||
|
||||
<br />
|
||||
<button class="button is-primary" [routerLink]="['/administration/step/4']">
|
||||
Revenir en arrière
|
||||
</button>
|
||||
</span>
|
||||
<span *ngIf="pollService.admin_key">
|
||||
a bien été créé !
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="container padded">
|
||||
<div class="has-text-centered">
|
||||
<div class=" ">
|
||||
<div class="main-block">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="admin">
|
||||
<div class="no-admin-key padded has-background-danger" *ngIf="!pollService.admin_key">
|
||||
Pas de clé d'administration, l'enregistrement du sondage a échoué. vérifiez vos paramètres
|
||||
réseau.
|
||||
</div>
|
||||
<div class="admin-ok" *ngIf="pollService.admin_key">
|
||||
<h2 class="title is-2">
|
||||
<i class="fa fa-gears"></i>
|
||||
{{ 'resume.admins' | translate }}
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
Voici les liens d’accès au sondage, conservez-les soigneusement ! (Si vous les perdez vous pourrez
|
||||
toujours les recevoir par email)
|
||||
Voici les liens d’accès au sondage, conservez-les soigneusement ! (Si vous les perdez
|
||||
vous pourrez toujours les recevoir par email)
|
||||
</p>
|
||||
<h2 class="title is-2">
|
||||
Côté admin
|
||||
</h2>
|
||||
<p>
|
||||
<div>
|
||||
Pour accéder au sondage et à tous ses paramètres :
|
||||
<br />
|
||||
<a class="button is-info" routerLink="/admin/{{ poll.admin_key }}"
|
||||
>{{ pollService.getAdministrationUrl() }}
|
||||
</a>
|
||||
<app-copy-text [textToCopy]="pollService.getAdministrationUrl()"></app-copy-text>
|
||||
</p>
|
||||
<pre class="is-default" routerLink="{{ pollService.getAdministrationUrlFromForm() }}"
|
||||
>{{ pollService.getAdministrationUrlFromForm() }}
|
||||
</pre
|
||||
>
|
||||
<app-copy-text
|
||||
[textToCopy]="pollService.getAdministrationUrlFromForm()"
|
||||
></app-copy-text>
|
||||
</div>
|
||||
<br />
|
||||
<a class="button is-info" [href]="pollService.getAdministrationUrl()">
|
||||
<a class="button is-info" [href]="pollService.getAdministrationUrlFromForm()">
|
||||
Voir le sondage coté administrateur·ice
|
||||
</a>
|
||||
|
||||
<br />
|
||||
<p class="note">
|
||||
Note : Le sondage sera supprimé {{ poll.default_expiracy_days_from_now }} jours après la date de sa
|
||||
dernière modification.
|
||||
<span class="expiracy-detail" *ngIf="poll.expiracy_date">
|
||||
Le {{ poll.expiracy_date | date: 'short' }}
|
||||
<p class="note has-background-info padded">
|
||||
<i class="fa fa-info-circle"></i> Note : Le sondage sera supprimé
|
||||
<strong> {{ pollService.form.value.expiresDaysDelay }} </strong> jours après la date de
|
||||
sa dernière modification.
|
||||
<span class="expiracy-detail" *ngIf="pollService.form.value.expiresDaysDelay">
|
||||
Le
|
||||
{{
|
||||
pollService.DateUtilitiesService.addDaysToDate(
|
||||
pollService.form.value.expiresDaysDelay,
|
||||
today
|
||||
) | date: 'short'
|
||||
}}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="public">
|
||||
<h2 class="title is-2" i18n>{{ 'resume.users' | translate }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="public" *ngIf="pollService.admin_key">
|
||||
<h2 class="title is-2">
|
||||
<i class="fa fa-ellipsis-v"></i>
|
||||
{{ 'resume.users' | translate }}
|
||||
</h2>
|
||||
<p>
|
||||
Pour voir le sondage :
|
||||
<br />
|
||||
<a class="button is-info" routerLink="/poll/{{ poll.custom_url }}/consultation"
|
||||
>{{ pollService.getParticipationUrl() }}
|
||||
<a class="button is-info" [href]="pollService.getParticipationUrlFromForm()"
|
||||
>{{ pollService.getParticipationUrlFromForm() }}
|
||||
</a>
|
||||
</p>
|
||||
<br />
|
||||
<app-copy-text [textToCopy]="pollService.getParticipationUrl()"></app-copy-text>
|
||||
<app-copy-text [textToCopy]="pollService.getParticipationUrlFromForm()"></app-copy-text>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<!-- <img src="assets/img/undraw_group_selfie_ijc6.svg" alt="image succès" />-->
|
||||
</div>
|
||||
<section class="mail">
|
||||
<h2 i18n>{{ 'resume.links_mail' | translate }}</h2>
|
||||
<p>
|
||||
<label for="email">
|
||||
Pour être sûr de retrouver ces liens, nous pouvons vous les envoyer sur votre mail :
|
||||
</label>
|
||||
<br />
|
||||
<input type="email" id="email" name="email" [(ngModel)]="poll.creatorEmail" placeholder="email" />
|
||||
<br />
|
||||
<button class="btn btn--primary" (click)="sendToEmail()">
|
||||
Envoyer les liens du sondage
|
||||
<i class="fa fa-paper-plane" aria-hidden="true"></i>
|
||||
</button>
|
||||
<br />
|
||||
<br />
|
||||
<a class="button is-info" href="{{ poll.custom_url }}">
|
||||
Voir le sondage côté public
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,3 +1,5 @@
|
||||
@import './src/styles/variables';
|
||||
|
||||
.button,
|
||||
a,
|
||||
button {
|
||||
@ -5,6 +7,7 @@ button {
|
||||
margin-right: 1ch;
|
||||
}
|
||||
a {
|
||||
padding: 1em;
|
||||
max-width: 20em;
|
||||
@extend .truncate;
|
||||
}
|
||||
@ -13,3 +16,9 @@ a {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
:host {
|
||||
padding: 2em;
|
||||
}
|
||||
.has-background-success {
|
||||
background: $logo_color_2 !important;
|
||||
}
|
||||
|
@ -15,12 +15,14 @@ export class SuccessComponent {
|
||||
mailToRecieve: string;
|
||||
window: any = window;
|
||||
environment = environment;
|
||||
today: Date = new Date();
|
||||
constructor(public pollService: PollService, private dateUtils: DateUtilitiesService, private titleService: Title) {
|
||||
this.titleService.setTitle(environment.appTitle + ' - 🎉 succès de création de sondage -');
|
||||
this.titleService.setTitle(
|
||||
environment.appTitle + ' - 🎉 succès de création de sondage - ' + this.pollService.form.value.title
|
||||
);
|
||||
|
||||
this.pollService.poll.subscribe((newpoll: Poll) => {
|
||||
this.poll = newpoll;
|
||||
// this.poll.expiracy_date = this.getExpiracyDateFromPoll(this.poll);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import { PasswordPromptComponent } from './password/password-prompt/password-pro
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'secure/:pass_hash', component: ConsultationComponent },
|
||||
|
||||
{ path: 'prompt', component: PasswordPromptComponent },
|
||||
{ path: 'simple', component: WipTodoComponent },
|
||||
{ path: 'table', component: WipTodoComponent },
|
||||
|
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="message is-warning" *ngIf="poll && poll.admin_key">
|
||||
<div class="message-body">
|
||||
vous êtes admin de ce sondage
|
||||
vous êtes admin de ce sondage et pouvez le modifier
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -60,15 +60,15 @@ export class ConsultationComponent implements OnInit, OnDestroy {
|
||||
|
||||
console.log('this.pass_hash ', this.pass_hash);
|
||||
if (this.pass_hash) {
|
||||
this.pollService.loadPollBycustom_urlWithPasswordHash(this.pollSlug, this.pass_hash).then((resp) => {
|
||||
console.log('resp', resp);
|
||||
this.pollService.loadPollByCustomUrlWithPasswordHash(this.pollSlug, this.pass_hash).then((resp) => {
|
||||
console.log('loadPollByCustomUrlWithPasswordHash resp', resp);
|
||||
this.fetching = false;
|
||||
this.storageService.vote_stack.id = null;
|
||||
this.storageService.setChoicesForVoteStack(this.pollService._poll.getValue().choices);
|
||||
});
|
||||
} else {
|
||||
this.pollService.loadPollBycustom_url(this.pollSlug).then((resp) => {
|
||||
console.log('resp', resp);
|
||||
this.pollService.loadPollByCustomUrl(this.pollSlug).then((resp) => {
|
||||
console.log('loadPollByCustomUrl resp', resp);
|
||||
this.fetching = false;
|
||||
this.storageService.vote_stack.id = null;
|
||||
this.storageService.setChoicesForVoteStack(this.pollService._poll.getValue().choices);
|
||||
@ -131,9 +131,9 @@ export class ConsultationComponent implements OnInit, OnDestroy {
|
||||
this.storageService.mapVotes(voteStack.data);
|
||||
this.pollService.enrichVoteStackWithCurrentPollChoicesDefaultVotes(this.storageService.vote_stack);
|
||||
if (this.pass_hash) {
|
||||
this.pollService.loadPollBycustom_urlWithPasswordHash(this.poll.custom_url, this.pass_hash);
|
||||
this.pollService.loadPollByCustomUrlWithPasswordHash(this.poll.custom_url, this.pass_hash);
|
||||
} else {
|
||||
this.pollService.loadPollBycustom_url(this.poll.custom_url);
|
||||
this.pollService.loadPollByCustomUrl(this.poll.custom_url);
|
||||
}
|
||||
} else {
|
||||
this.toastService.display('erreur à l enregistrement');
|
||||
|
@ -9,6 +9,8 @@ import { PollResultsCompactComponent } from './poll-results-compact/poll-results
|
||||
import { PollResultsDetailedComponent } from './poll-results-detailed/poll-results-detailed.component';
|
||||
import { ChoiceButtonComponent } from '../../shared/components/choice-item/choice-button.component';
|
||||
import { PasswordPromptComponent } from './password/password-prompt/password-prompt.component';
|
||||
import { ChoiceDetailsComponent } from '../../shared/components/choice-details/choice-details.component';
|
||||
import { CoreModule } from '../../core/core.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -1,7 +1,6 @@
|
||||
@import '../../../../styles/variables';
|
||||
|
||||
.box {
|
||||
border-left: 3px solid white;
|
||||
cursor: pointer;
|
||||
* {
|
||||
cursor: pointer;
|
||||
|
@ -77,11 +77,11 @@ export class PollResultsDetailedComponent {
|
||||
if (voteStack.status == 200) {
|
||||
this.storageService.mapVotes(voteStack.data);
|
||||
this.pollService.enrichVoteStackWithCurrentPollChoicesDefaultVotes(this.storageService.vote_stack);
|
||||
// if (this.pass_hash) {
|
||||
// this.pollService.loadPollBycustom_urlWithPasswordHash(this.poll.custom_url, this.pass_hash);
|
||||
// } else {
|
||||
this.pollService.loadPollBycustom_url(this.poll.custom_url);
|
||||
// }
|
||||
if (this.pollService.pass_hash) {
|
||||
this.pollService.loadPollByCustomUrlWithPasswordHash(this.poll.custom_url, this.pollService.pass_hash);
|
||||
} else {
|
||||
this.pollService.loadPollByCustomUrl(this.poll.custom_url);
|
||||
}
|
||||
} else {
|
||||
this.toastService.display('erreur à l enregistrement');
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
<div
|
||||
class="validation-error-list padded"
|
||||
*ngIf="(form.valid && !hide_on_valid) || !form.valid"
|
||||
[ngClass]="{ 'has-background-warning': totalErrors > 0, 'has-background-success': totalErrors === 0 }"
|
||||
>
|
||||
<h1 class="title is-1">
|
||||
@ -24,4 +25,10 @@
|
||||
{{ m }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="debug" *ngIf="!environment.production">
|
||||
<pre>
|
||||
{{ messages | json }}
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,3 +7,6 @@
|
||||
color: white;
|
||||
border: solid 2px white;
|
||||
}
|
||||
.validation-error-list {
|
||||
margin: 2em;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { FormGroup, ValidationErrors } from '@angular/forms';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { environment } from '../../../../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-errors-list',
|
||||
@ -12,6 +13,8 @@ export class ErrorsListComponent implements OnInit {
|
||||
public totalErrors = 0;
|
||||
public firstErrorId = '';
|
||||
public messages = [];
|
||||
public hide_on_valid = true;
|
||||
public environment = environment;
|
||||
|
||||
constructor(@Inject(DOCUMENT) private document: any) {}
|
||||
|
||||
|
@ -20,13 +20,6 @@ export const routes: Routes = [
|
||||
data: { animation: 'AdminPage' },
|
||||
loadChildren: () =>
|
||||
import('./features/administration/administration.module').then((m) => m.AdministrationModule),
|
||||
// resolve: { poll: PollService },
|
||||
},
|
||||
{
|
||||
path: 'admin/:admin_key',
|
||||
loadChildren: () =>
|
||||
import('./features/administration/administration.module').then((m) => m.AdministrationModule),
|
||||
// resolve: { poll: PollService },
|
||||
},
|
||||
{
|
||||
path: 'poll/:custom_url/consultation',
|
||||
|
@ -1,9 +1,7 @@
|
||||
<section class="hero is-warning is-medium">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title has-text-centered">
|
||||
{{ message | translate }}
|
||||
</h1>
|
||||
<h1 class="title has-text-centered">o_O {{ message | translate }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -5,7 +5,8 @@
|
||||
"home": {
|
||||
"title": "Bienvenue sur",
|
||||
"subtitle": "Se consulter simplement pour s’organiser collectivement.",
|
||||
"search_title": "Où sont mes sondages? ",
|
||||
"search_title": "Vous avez déjà créé un sondage et vous souhaitez y accéder ?",
|
||||
"search_subtitle": "Saisissez votre adresse e-mail et nous vous enverrons le lien vers votre sondage. ",
|
||||
"create_button": "Créer un nouveau sondage ",
|
||||
"search_button": "Rechercher"
|
||||
},
|
||||
@ -27,13 +28,14 @@
|
||||
},
|
||||
"creation": {
|
||||
"title": "Créer un sondage",
|
||||
"want": "Je veux créer un sondage",
|
||||
"want": "Choisissez le type de sondage",
|
||||
"advanced": "Options avancées",
|
||||
"kind": {
|
||||
"classic": "classique",
|
||||
"date": "spécial dates"
|
||||
"classic": "Propositions",
|
||||
"date": "Date"
|
||||
},
|
||||
"choose_title": "Dont le titre sera",
|
||||
"choose_title": "Renseignez un nom pour votre sondage",
|
||||
"choose_title_label": "Nom de votre sondage (obligatoire)",
|
||||
"choose_title_placeholder": "titre",
|
||||
"choices_hint": "Utilisez les flèches haut ⬆️ et bas ⬇️ pour passer d'un choix à un autre",
|
||||
"name": "Je peux aussi préciser mon nom si je le souhaite",
|
||||
@ -72,7 +74,7 @@
|
||||
"continue": "Voyons ce que ça donne"
|
||||
},
|
||||
"resume": {
|
||||
"title": "Et c'est tout pour nous !",
|
||||
"title": "Félicitations !",
|
||||
"admins": "Côté administrateur-ice-eux",
|
||||
"users": "Côté sondés",
|
||||
"links_mail": "Recevoir les liens par e-mail"
|
||||
@ -144,7 +146,8 @@
|
||||
"selectors": {
|
||||
"lang": "Sélectionner la langue"
|
||||
},
|
||||
"validation" : {
|
||||
"validation": {
|
||||
"required": "champ requis",
|
||||
"You must enter a value": "You must enter a EEEE"
|
||||
},
|
||||
"You must enter a value": "You must enter a valueeeeeeee",
|
||||
@ -576,8 +579,7 @@
|
||||
"the-administrator-locked-this-poll-votes-and-comments-are-frozen-it-is-no-longer-possible-to-partici": "L'administrateur·rice a verrouillé ce sondage. Les votes et commentaires sont gelés, il n'est plus possible de participer",
|
||||
"the-poll-has-expired-it-will-soon-be-deleted": "Le sondage a expiré, il sera bientôt supprimé.",
|
||||
"your-vote-has-been-saved-but-please-note-you-need-to-keep-this-personalised-link-to-be-able-to-edit-": "Votre vote a bien été pris en compte, mais faites attention : ce sondage n'autorise l'édition de votre vote qu'avec le lien personnalisé suivant ; conservez-le précieusement !"
|
||||
}
|
||||
,
|
||||
},
|
||||
"LANGUAGES": {
|
||||
"DE": "Allemand",
|
||||
"FR": "Français",
|
||||
@ -593,8 +595,8 @@
|
||||
"OC": "oc",
|
||||
"SV": "sv"
|
||||
},
|
||||
"calendar_widget" : {
|
||||
"startsWith": "Starts with",
|
||||
"calendar_widget": {
|
||||
"startsWith": "Commence par",
|
||||
"contains": "Contains",
|
||||
"notContains": "Not contains",
|
||||
"endsWith": "Ends with",
|
||||
@ -605,27 +607,77 @@
|
||||
"lte": "Less than or equal to",
|
||||
"gt": "Greater than",
|
||||
"gte": "Great then or equals",
|
||||
"is": "Is",
|
||||
"isNot": "Is not",
|
||||
"before": "Before",
|
||||
"after": "After",
|
||||
"clear": "Clear",
|
||||
"apply": "Apply",
|
||||
"is": "Est",
|
||||
"isNot": "N'est pas",
|
||||
"before": "Avant",
|
||||
"after": "Après",
|
||||
"clear": "Vider",
|
||||
"apply": "Appliquer",
|
||||
"matchAll": "Match All",
|
||||
"matchAny": "Match Any",
|
||||
"addRule": "Add Rule",
|
||||
"removeRule": "Remove Rule",
|
||||
"accept": "Yes",
|
||||
"reject": "No",
|
||||
"choose": "Choose",
|
||||
"accept": "Oui",
|
||||
"reject": "Non",
|
||||
"choose": "Choisir",
|
||||
"upload": "Upload",
|
||||
"cancel": "Cancel",
|
||||
"dayNames": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
||||
"dayNamesShort": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||
"dayNamesMin": ["Su","Mo","Tu","We","Th","Fr","Sa"],
|
||||
"monthNames": ["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"],
|
||||
"monthNamesShort": ["Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
||||
"cancel": "Annuler",
|
||||
"dayNames": [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday"
|
||||
],
|
||||
"dayNamesShort": [
|
||||
"Dim",
|
||||
"Lun",
|
||||
"Mar",
|
||||
"Mer",
|
||||
"Jeu",
|
||||
"Ven",
|
||||
"Sam"
|
||||
],
|
||||
"dayNamesMin": [
|
||||
"Di",
|
||||
"Lu",
|
||||
"Ma",
|
||||
"Me",
|
||||
"Je",
|
||||
"Ve",
|
||||
"Sa"
|
||||
],
|
||||
"monthNames": [
|
||||
"Janvier",
|
||||
"Février",
|
||||
"Mars",
|
||||
"Avril",
|
||||
"Mai",
|
||||
"Juin",
|
||||
"Juillet",
|
||||
"Août",
|
||||
"Septembre",
|
||||
"Octobre",
|
||||
"Novembre",
|
||||
"Décembre"
|
||||
],
|
||||
"monthNamesShort": [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"today": "Aujourd'hui",
|
||||
"weekHeader": "Wk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
src/assets/img/icone_home.png
Normal file
BIN
src/assets/img/icone_home.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
src/assets/img/where-is-it.jpg
Normal file
BIN
src/assets/img/where-is-it.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
@ -1,15 +1,15 @@
|
||||
export const backendApiUrlsInDev = {
|
||||
// local: 'http://tktest.lan/api/v1',
|
||||
// remote: 'http://tktest.lan/api/v1',
|
||||
// local: 'https://localhost:8000/api/v1',
|
||||
local: 'https://framadate-api.cipherbliss.com/api/v1',
|
||||
// remote: 'https://localhost:8000/api/v1',
|
||||
remote: 'https://framadate-api.cipherbliss.com/api/v1',
|
||||
local: 'http://localhost:8000/api/v1',
|
||||
// local: 'https://framadate-api.cipherbliss.com/api/v1',
|
||||
remote: 'http://localhost:8000/api/v1',
|
||||
// remote: 'https://framadate-api.cipherbliss.com/api/v1',
|
||||
};
|
||||
export const apiV1 = {
|
||||
// baseHref: 'https://localhost:8000/api/v1',
|
||||
baseHref: 'http://localhost:8000/api/v1',
|
||||
// baseHref: 'http://tktest.lan/api/v1',
|
||||
baseHref: 'https://framadate-api.cipherbliss.com/api/v1',
|
||||
// baseHref: 'https://framadate-api.cipherbliss.com/api/v1',
|
||||
api_new_poll: '/poll/',
|
||||
api_get_poll: '/poll/{id}',
|
||||
api_new_vote_stack: '/vote-stack',
|
||||
|
@ -16,9 +16,12 @@ export const environment = {
|
||||
production: true,
|
||||
display_routes: true,
|
||||
showDemoWarning: true,
|
||||
autofill: false,
|
||||
autofill_creation: true,
|
||||
autofill_participation: true,
|
||||
advanced_options_display: false,
|
||||
autoSendNewPoll: false,
|
||||
interval_days_default: 7,
|
||||
showStepperShortcuts: true,
|
||||
expiresDaysDelay: 60,
|
||||
maxCountOfAnswers: 150,
|
||||
appTitle: 'FramaDate Funky',
|
||||
|
@ -10,15 +10,19 @@ endpoints.baseHref = apiV1.baseHref;
|
||||
export const environment = {
|
||||
frontDomain: 'http://127.0.0.1:4200',
|
||||
production: false,
|
||||
display_routes: true,
|
||||
autofill: true,
|
||||
display_routes: true, // demo paths to test polls
|
||||
autofill_creation: true,
|
||||
advanced_options_display: true,
|
||||
autofill_participation: true,
|
||||
// autofill: false,
|
||||
showDemoWarning: true,
|
||||
showDemoWarning: false,
|
||||
// autoSendNewPoll: true,
|
||||
autoSendNewPoll: false,
|
||||
showStepperShortcuts: true,
|
||||
interval_days_default: 7,
|
||||
expiresDaysDelay: 60,
|
||||
maxCountOfAnswers: 150,
|
||||
appTitle: 'Framadate Funky',
|
||||
appTitle: 'Framadate',
|
||||
appVersion: '0.6.0',
|
||||
appLogo: 'assets/img/logo.png',
|
||||
api: endpoints,
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Update Bulma's global variables
|
||||
$family-sans-serif: 'Nunito', sans-serif;
|
||||
|
||||
$primary: $dark-lavender;
|
||||
$primary: $primary_color;
|
||||
$link: $wisteria;
|
||||
$widescreen-enabled: false;
|
||||
$fullhd-enabled: false;
|
||||
|
@ -1,4 +1,32 @@
|
||||
@charset "UTF-8";
|
||||
.input:hover,
|
||||
input:hover,
|
||||
select:hover,
|
||||
.textarea:hover,
|
||||
.select select:hover,
|
||||
.is-hovered.input,
|
||||
input.is-hovered,
|
||||
select.is-hovered,
|
||||
.is-hovered.textarea,
|
||||
.select select.is-hovered {
|
||||
border-color: $border-color !important;
|
||||
}
|
||||
app-step-one,
|
||||
app-step-two,
|
||||
app-step-three,
|
||||
app-step-four {
|
||||
padding: 2em 2.5em;
|
||||
display: block;
|
||||
}
|
||||
app-step-five {
|
||||
app-stepper {
|
||||
padding: 2em 2.5em;
|
||||
display: block;
|
||||
}
|
||||
.container {
|
||||
padding: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
@ -212,18 +240,18 @@ mat-checkbox {
|
||||
.ng-pristine,
|
||||
.ng-dirty {
|
||||
//border-left: #ccc 3px solid;
|
||||
padding-left: 1em;
|
||||
//padding-left: 1em;
|
||||
}
|
||||
|
||||
.ng-touched.ng-invalid {
|
||||
border-left: $danger 3px solid;
|
||||
padding-left: 1em;
|
||||
//border-left: $danger 3px solid;
|
||||
//padding-left: 1em;
|
||||
}
|
||||
|
||||
.theme-dark-crystal {
|
||||
.ng-touched.ng-valid {
|
||||
border-left: $success 3px solid;
|
||||
padding-left: 1em;
|
||||
//border-left: $success 3px solid;
|
||||
//padding-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,3 +263,86 @@ mat-checkbox {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
// calendar primeng
|
||||
.p-datepicker {
|
||||
border: solid 1px $logo_color;
|
||||
padding: 0.5em;
|
||||
margin: 1em auto;
|
||||
|
||||
button {
|
||||
border: solid 1px $primary_color;
|
||||
}
|
||||
.p-datepicker-buttonbar {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.pi-chevron-left:after {
|
||||
content: '<';
|
||||
}
|
||||
|
||||
.pi-chevron-right:after {
|
||||
content: '>';
|
||||
}
|
||||
|
||||
.p-datepicker-month {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.p-datepicker-weeknumber span {
|
||||
border-right: 1px solid $legend_color;
|
||||
}
|
||||
|
||||
.p-datepicker-today span {
|
||||
font-weight: bold;
|
||||
border: solid 1px $legend_color;
|
||||
}
|
||||
|
||||
.p-datepicker-calendar td span {
|
||||
padding: 1em;
|
||||
width: 3.5em;
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&:hover {
|
||||
background: mix($white, $legend_color);
|
||||
color: $white;
|
||||
transition: all ease 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.p-highlight {
|
||||
background: $legend_color;
|
||||
color: $white;
|
||||
border-radius: 100%;
|
||||
}
|
||||
.p-disabled {
|
||||
background: $d-grey;
|
||||
color: $grey;
|
||||
}
|
||||
.p-datepicker-other-month {
|
||||
color: white;
|
||||
}
|
||||
// weekend days
|
||||
tr > td {
|
||||
&:nth-of-type(6),
|
||||
&:nth-of-type(7) {
|
||||
//border-left: 1px solid $border-color;
|
||||
background: $grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-config {
|
||||
.box {
|
||||
background: $light;
|
||||
border: 3px solid $primary-color;
|
||||
}
|
||||
.work-in-progress {
|
||||
padding: 1em 2em;
|
||||
background: $border-color;
|
||||
color: $light;
|
||||
}
|
||||
}
|
||||
|
||||
.step-container {
|
||||
@extend .container, .is-widescreen;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@
|
||||
.legend {
|
||||
font-size: 14px;
|
||||
margin-left: 14px;
|
||||
color: $dark-lavender;
|
||||
color: $primary-light;
|
||||
}
|
||||
|
||||
.legend_first {
|
||||
|
@ -4,24 +4,9 @@ main {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
.main-block {
|
||||
min-height: 20em;
|
||||
max-width: 40em;
|
||||
margin-bottom: 10em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
.title {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
.button {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.creation,
|
||||
.search {
|
||||
@extend .main-block;
|
||||
@extend main;
|
||||
}
|
||||
|
@ -7,3 +7,11 @@ html {
|
||||
main {
|
||||
min-height: 90vh;
|
||||
}
|
||||
.min-height {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
min-height: 50vh;
|
||||
}
|
||||
.content {
|
||||
padding: 1em;
|
||||
}
|
||||
|
@ -2,10 +2,8 @@
|
||||
background: $primary;
|
||||
|
||||
main {
|
||||
padding: 0;
|
||||
margin-bottom: 2em;
|
||||
padding-bottom: 5em;
|
||||
padding-top: 1em;
|
||||
background: $white;
|
||||
}
|
||||
.big-header {
|
||||
|
@ -1,106 +1,62 @@
|
||||
@charset "UTF-8";
|
||||
// ****************************** config ******************************
|
||||
$theme-vars: 'violet'; // violet , blue
|
||||
|
||||
// ****************************** colors from styleguide https://app.zeplin.io/project/5d4d83d68866d6522ff2ff10/styleguide/colors?cid=5d502bb032e23e3516af8154
|
||||
// colors from styleguide https://app.zeplin.io/project/5d4d83d68866d6522ff2ff10/styleguide/colors?cid=5d502bb032e23e3516af8154
|
||||
$green: #64d16e;
|
||||
$black: #000000;
|
||||
$ugly-purple: #b24eb7;
|
||||
$lavender-pink: #e9bdeb;
|
||||
$white: #ffffff;
|
||||
$dark-lavender: #7d6c99;
|
||||
$dusty-orange: #f18647;
|
||||
$violet: #bd10e0;
|
||||
$red: #cd0000;
|
||||
$cool-grey: #aeafb1;
|
||||
$warm-grey: #807e7e;
|
||||
|
||||
$green: #64d16e;
|
||||
$dusty-orange: #f18647;
|
||||
$red: #cd0000;
|
||||
$pink: #fa7c91;
|
||||
|
||||
$purple: #8a4d76;
|
||||
$ugly-purple: #b24eb7;
|
||||
$violet: #bd10e0;
|
||||
$wisteria: #bf83c2;
|
||||
$pale-purple: #d198d4;
|
||||
$lavender-pink: #e9bdeb;
|
||||
$dark-lavender: #7d6c99;
|
||||
|
||||
// themes ****************************** blue variation around styleguide
|
||||
$blueish-green: #64d1a9;
|
||||
$blueish-dusty-orange: #74a389;
|
||||
$blueish-red: #9d00cd;
|
||||
$blueish-pink: #d47cfa;
|
||||
$blueish-purple: #4d4d8a;
|
||||
$blueish-ugly-purple: #4d5b8a;
|
||||
$blueish-violet: #5810bd;
|
||||
$blueish-wisteria: #8b83bf;
|
||||
$blueish-pale-purple: #8a9bd1;
|
||||
$blueish-lavender-pink: #8a97e9;
|
||||
$blueish-dark-lavender: #7d6c8a;
|
||||
$blueish-brown: #636c77;
|
||||
|
||||
$purple: #8a4d76;
|
||||
$pink: #fa7c91;
|
||||
$brown: #757763;
|
||||
$beige-light: #d0d1cd;
|
||||
$beige-lighter: #eff0eb;
|
||||
|
||||
// ****************************** interpretations in app
|
||||
// DINUM colors
|
||||
|
||||
$primary_color: $ugly-purple;
|
||||
$primary: $ugly-purple;
|
||||
$secondary_color: $lavender-pink;
|
||||
$d-primary: #3e3882; // bleu 800
|
||||
$d-primary-intense: #6359cf; // bleu 600
|
||||
$d-grey: #f6f5fd;
|
||||
$d-neutral: #767486;
|
||||
$d-alt: #a9607f;
|
||||
|
||||
$d-info: #ecf4ff;
|
||||
$d-info-text: #316ec7;
|
||||
$d-success: #ecfff5;
|
||||
$d-success-text: #128149;
|
||||
$d-warning: #dcd3bb;
|
||||
$d-warning-text: #86671b;
|
||||
$d-error: #ffecee;
|
||||
$d-error-text: #d51b38;
|
||||
|
||||
// interpretations in app
|
||||
$primary_color: $d-primary;
|
||||
$primary: $d-primary;
|
||||
$secondary_color: $d-primary-intense;
|
||||
$font_color: $black;
|
||||
$logo_color: $dark-lavender;
|
||||
$logo_color_2: $green;
|
||||
$legend_color: $dark-lavender;
|
||||
$legend_color_2: $dusty-orange;
|
||||
$choice_select_border_color: $cool-grey;
|
||||
$hover-color: $warm-grey;
|
||||
$grey-dark: $warm-grey;
|
||||
$grey-light: $beige-light;
|
||||
$clicked-color: $wisteria;
|
||||
$mini-button-color: $pale-purple;
|
||||
$warning: $dusty-orange;
|
||||
$danger: $red;
|
||||
$success: $green;
|
||||
// ****************************** render ******************************
|
||||
@if $theme-vars == 'violet' {
|
||||
$primary_color: $ugly-purple;
|
||||
$primary: $ugly-purple;
|
||||
$secondary_color: $lavender-pink;
|
||||
$font_color: $black;
|
||||
$logo_color: $dark-lavender;
|
||||
$logo_color_2: $green;
|
||||
$legend_color: $dark-lavender;
|
||||
$legend_color_2: $dusty-orange;
|
||||
$choice_select_border_color: $cool-grey;
|
||||
$hover-color: $warm-grey;
|
||||
$grey-dark: $warm-grey;
|
||||
$grey-light: $beige-light;
|
||||
$clicked-color: $wisteria;
|
||||
$mini-button-color: $pale-purple;
|
||||
$warning: $dusty-orange;
|
||||
$danger: $red;
|
||||
$success: $green;
|
||||
$logo_color: $d-primary;
|
||||
$logo_color_2: $d-primary-intense;
|
||||
$legend_color: $d-info-text;
|
||||
$legend_color_2: $d-info;
|
||||
$choice_select_border_color: $d-info;
|
||||
$hover-color: $d-neutral;
|
||||
$border-color: $d-neutral;
|
||||
$grey-dark: $d-primary;
|
||||
$grey-lighter: $beige-light;
|
||||
$clicked-color: $d-primary;
|
||||
$mini-button-color: $d-primary-intense;
|
||||
$warning: $d-warning;
|
||||
$danger: $d-error;
|
||||
$success: $d-success;
|
||||
|
||||
// FONT
|
||||
$default_font: 'pt_sans';
|
||||
$title_font: 'proza_libre', 'Brie Light', 'Arial', 'DejaVu Sans Mono';
|
||||
} @else if $theme-vars == 'blue' {
|
||||
$primary_color: $blueish-ugly-purple;
|
||||
$primary: $blueish-ugly-purple;
|
||||
$secondary_color: $blueish-lavender-pink;
|
||||
$font_color: $black;
|
||||
$logo_color: $blueish-dark-lavender;
|
||||
$logo_color_2: $blueish-green;
|
||||
$legend_color: $blueish-dark-lavender;
|
||||
$legend_color_2: $blueish-dusty-orange;
|
||||
$choice_select_border_color: $cool-grey;
|
||||
$hover-color: $warm-grey;
|
||||
$grey-dark: $warm-grey;
|
||||
$grey-light: $beige-light;
|
||||
$clicked-color: $blueish-wisteria;
|
||||
$mini-button-color: $blueish-pale-purple;
|
||||
$warning: $blueish-dusty-orange;
|
||||
$danger: $blueish-red;
|
||||
$success: $blueish-green;
|
||||
|
||||
// FONT
|
||||
$default_font: 'pt_sans';
|
||||
$title_font: 'proza_libre', 'Brie Light', 'Arial', 'DejaVu Sans Mono';
|
||||
}
|
||||
$default_font: 'pt_sans';
|
||||
$title_font: 'proza_libre', 'Brie Light', 'Arial', 'DejaVu Sans Mono';
|
||||
|
19
yarn.lock
19
yarn.lock
@ -2150,6 +2150,13 @@ amdefine@>=0.0.4:
|
||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
|
||||
|
||||
angular-date-value-accessor@^1.0.2:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/angular-date-value-accessor/-/angular-date-value-accessor-1.2.1.tgz#a5f07b11fef1c0d1fde5aa851057de177c510137"
|
||||
integrity sha512-4lhVi5PRpaIKtsCDEHioue324u1j18t46ZrD/jI7+M6DrZeRyxfMeSGsZXWNOC6eaq9x/pzXyaE8slXSj3Qd5A==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
ansi-align@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
|
||||
@ -3755,6 +3762,11 @@ crypto-random-string@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
||||
|
||||
crypto@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037"
|
||||
integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==
|
||||
|
||||
css-color-names@0.0.4, css-color-names@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
||||
@ -9451,6 +9463,13 @@ pretty-format@^26.0.0, pretty-format@^26.1.0:
|
||||
ansi-styles "^4.0.0"
|
||||
react-is "^16.12.0"
|
||||
|
||||
primeng@^11.0.0:
|
||||
version "11.4.5"
|
||||
resolved "https://registry.yarnpkg.com/primeng/-/primeng-11.4.5.tgz#128137d727d555f68c212a1dcb1f2af3b0f4afd4"
|
||||
integrity sha512-7f5LDHrvFsJA4670Ftmib5ndDxTqcaQiM88XXJrjWYNGjXsXT3Yc5g9fgPvDrg2D38/jjpcSYeW9kalNcvlbrQ==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
prismjs@^1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03"
|
||||
|
Loading…
Reference in New Issue
Block a user