Commit 2d492ac2 authored by Yorrd's avatar Yorrd
Browse files

feat: detail view, content admin improvements, etc

parent 8def655b
Pipeline #1372 passed with stages
in 10 minutes and 6 seconds
......@@ -65,5 +65,5 @@ generateFontResets('ccb', {
text: { ...fontReset(1, 0.1, 'Barlow'), fontSize: '18px' },
});
AdornisRouter.init(['/:page']);
AdornisRouter.init(['/:page/:content']);
import '@adornis/users/client/auto-relogin';
import { AdornisRouter } from '@adornis/adornis-components/a-router';
import { element, html, rerender, ScopingElement } from '@adornis/base';
import { EmotionMixin } from '@adornis/design';
import { Content } from 'imports/db';
import { switchMap, map } from 'rxjs/operators';
import { RenderProps } from 'imports/git_modules/base/reactive-lit-element';
import { Observable } from 'rxjs';
import { unsafeHTML } from 'imports/compile/lit-html/directives/unsafe-html';
import { format } from 'path';
import { AdornisUser } from 'imports/git_modules/users/db';
import { listenDevice, BreakPoint } from 'imports/git_modules/base/window-size';
@element('ccb-content-view')
export class ccbContentView extends EmotionMixin(ScopingElement) {
@rerender public content = AdornisRouter.get('content').pipe(
switchMap(content => Content.findOne({ _id: content }).whenReady),
) as Observable<Content>;
public render({ content }: RenderProps<ccbContentView>) {
if (!content)
return html`
content cannot be found
`;
return html`
<a-stack
vertical
size="md"
padding="${listenDevice.pipe(map(device => (device < BreakPoint.laptop ? 'md' : 'xl')))}"
class="${this.css({ background: 'white', width: '100vw', maxWidth: '1000px', margin: 'auto' })}"
>
<a-h1> ${content.Frage} </a-h1>
<a-text horizontal justified>
${AdornisUser.findOne({ _id: content.createdBy }).whenReady.pipe(map(user => user?.contactName || ''))}
${content.createdAt.toUTCString()}</a-text
>
<a-box
>${content.isRecent()
? html`
<mwc-icon class=${this.css({ color: 'green', userSelect: 'none' })}>check</mwc-icon>
`
: html`
<mwc-icon class=${this.css({ color: 'red', userSelect: 'none' })}>close</mwc-icon>
`}</a-box
>
<a-text>${content.country}</a-text>
<a-text>${unsafeHTML(content.Antwort)}</a-text>
<a-text
>Falls du weitere Fragen zu diesen Thema hast, kann dir ${content.Ansprechpartner} bestimmt
weiterhelfen.</a-text
>
<a-text class="${this.css({ cursor: 'pointer' })}" href="${content.Quelle}">
Quelle:
<a-text class=${this.css({ textDecoration: 'underline' })}> ${content.Quelle} </a-text>
</a-text>
</a-stack>
`;
}
}
import { element, html, rerender } from '@adornis/base';
import { AdornisDBView, AttributeField } from '@adornis/adornis-components/a-dbview';
import { Content } from 'imports/db/contents';
import { Content, Country } from 'imports/db/contents';
import { BehaviorSubject, of, combineLatest } from 'rxjs';
import { ifDefined } from 'lit-html/directives/if-defined';
import { takeUntil, distinctUntilChanged, map, switchMap, startWith } from 'rxjs/operators';
......@@ -18,6 +18,7 @@ import '@material/mwc-checkbox';
import { virtualize } from '@adornis/base/when-seen';
import { AdornisDialog } from 'imports/git_modules/adornis-components/a-dialog';
import { listenDevice, BreakPoint } from 'imports/git_modules/base/window-size';
import { repeat } from 'lit-html/directives/repeat';
@element('ccb-contents-admin')
export class CCBContentsAdmin extends AdornisDBView<Content> {
......@@ -101,20 +102,17 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
${this.fieldDisplays(this.getField('Antwort')!, entity, index)}
${this.fieldDisplays(this.getField('Quelle')!, entity, index)}
<a-stack horizontal centeraligned size="md">
${this.fieldDisplays(this.getField('Ansprechpartner')!, entity, index)}
<a-box
padding="md"
<div class="${this.css({ flex: '1' })}">
${this.fieldDisplays(this.getField('Ansprechpartner')!, entity, index)}
</div>
<ccb-button
@click="${() =>
AdornisDialog.showPopup(
resolve => html`
<a-box vertical elevation="2">
<a-box vertical elevation="2" padding="lg">
${rxRepeat(
AdornisUser.find().whenReady,
user => html`<a-box padding="md" style="${{
background: 'white',
maxHeight: '50vh',
overflow: 'auto',
}}" @click="${() => {
user => html`<a-box padding="md" style="background: white; max-height: 50vh; overflow: auto; cursor: pointer;" @click="${() => {
if (entity.createdBy !== user._id) entity.createdBy = user._id;
resolve();
}}">
......@@ -122,21 +120,19 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
</a-box>
</a-box>
`,
)}</a-box
)}<ccb-button secondary @click="${resolve}">Schließen</ccb-button></a-box
>
`,
)}"
>
<ccb-h4
>${entity.whenChanging.pipe(
switchMap(ent =>
AdornisUser.findOne({ _id: ent.createdBy }).whenReady.pipe(
map(user => (user ? 'Autor: ' + user.username : 'Autor zuweisen')),
),
${entity.whenChanging.pipe(
switchMap(ent =>
AdornisUser.findOne({ _id: ent.createdBy }).whenReady.pipe(
map(user => (user ? 'Autor: ' + user.username : 'Autor zuweisen')),
),
)}</ccb-h4
>
</a-box>
),
)}
</ccb-button>
</a-stack>
<ccb-stack horizontal centeraligned size="md">
<a-file-input @file-changed="${e => (fileToUpload = e.detail.file)}"></a-file-input>
......@@ -150,8 +146,31 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
>Datei hochladen</ccb-button
>
</ccb-stack>
<ccb-button @click="${() => entity.save()}"
secondary
<ccb-button
@click="${() =>
AdornisDialog.showPopup(
resolve => html`
<a-box vertical elevation="2" padding="lg">
${repeat(
Object.keys(Country),
countryKey => html`<a-box padding="md" style="background: white; max-height: 50vh; overflow: auto; cursor: pointer;" @click="${() => {
if (entity.country !== Country[countryKey]) entity.country = Country[countryKey];
resolve();
}}">
<ccb-h4>${Country[countryKey]}</ccb-h4>
</a-box>
</a-box>
`,
)}<ccb-button secondary @click="${resolve}">Schließen</ccb-button></a-box
>
`,
)}"
>
${entity.whenChanging.pipe(map(ent => (ent.country ? 'Land: ' + ent.country : 'Land zuweisen')))}
</ccb-button>
<ccb-button @click="${() => entity.save()}" secondary
>Diesen Inhalt als "aktuell" markieren (letzte Aktualisierung
${moment(entity.updateAt).format('DD.MM.YYYY HH:mm')})</ccb-button
>
......@@ -208,6 +227,7 @@ export class CCBContentsAdmin extends AdornisDBView<Content> {
case 'Ansprechpartner':
return html`
<mwc-textfield
style="width: 100%"
.label="${field.name}"
.value="${ifDefined(data[field.name])}"
@input="${e => {
......
import { element, html, ScopingElement } from 'imports/git_modules/base';
import { element, html, ScopingElement } from '@adornis/base';
import { EmotionMixin } from '@adornis/design';
import { map } from 'rxjs/operators';
import { AdornisRouter } from 'imports/git_modules/adornis-components/a-router';
import { AdornisRouter } from '@adornis/adornis-components/a-router';
@element('ccb-landing-page')
export class CCBLandingPage extends EmotionMixin(ScopingElement) {
......@@ -12,46 +12,77 @@ export class CCBLandingPage extends EmotionMixin(ScopingElement) {
switch (page) {
case '':
return html`
<a-stack size="xl">
<a-inline horizontal size="lg" padding="xl">
<a-stack size="md" class="${this.css({ flex: '1', minWidth: '300px' })}">
<ccb-text>Hi!</ccb-text>
<ccb-text
>Der Legal Chatbot gibt Ratsuchenden Antworten auf Ihre rechtlichen Fragen, die im Zuge der
Coronakrise entstanden sind.</ccb-text
>
<ccb-text
>Als Experte und Institution können Sie Ihre FAQs hier bereitstellen und diese regelmäßig
updaten. Über den Chatbot erhalten die Ratsuchenden Ihre Antworten</ccb-text
>
</a-stack>
<a-stack size="md" class="${this.css({ flex: '1', justifyContent: 'center', minWidth: '530px' })}">
<a-link href="https://t.me/CoronaLegalChatBot" target="_blank"
><ccb-button>Zum Legal Chatbot für&nbsp;<b>Ratsuchende</b></ccb-button></a-link
>
<a-link href="/contentadmin">
<ccb-button secondary
>Als&nbsp;<b>Institution</b>&nbsp;FAQs hinterlassen (bspw. LandesReg.)</ccb-button
<a-box fullbleed centered>
x
<a-stack size="xl">
<a-inline horizontal size="lg" padding="xl">
<a-stack size="md" class="${this.css({ flex: '1', minWidth: '300px' })}">
<ccb-text>Hi!</ccb-text>
<ccb-text>
Der Legal Chatbot gibt Ratsuchenden Antworten auf Ihre rechtlichen Fragen, die im Zuge der
Coronakrise entstanden sind.
</ccb-text>
<ccb-text
>Als Experte und Institution können Sie Ihre FAQs hier bereitstellen und diese regelmäßig
updaten. Über den Chatbot erhalten die Ratsuchenden Ihre Antworten</ccb-text
>
</a-link>
<a-link href="/contentadmin">
<ccb-button secondary
>Als&nbsp;<b>Experte</b>&nbsp;FAQs hinterlassen (bspw. Kanzlei)</ccb-button
</a-stack>
<a-stack
size="md"
class="${this.css({ flex: '1', justifyContent: 'center', minWidth: '400px' })}"
>
<a-link href="https://t.me/CoronaLegalChatBot" target="_blank"
><ccb-button>Zum Legal Chatbot für&nbsp;<b>Ratsuchende</b></ccb-button></a-link
>
</a-link>
<a-link href="/contentadmin">
<ccb-button secondary
>Als&nbsp;<b>Institution</b>&nbsp;FAQs hinterlassen (bspw. LandesReg.)</ccb-button
>
</a-link>
<a-link href="/contentadmin">
<ccb-button secondary
>Als&nbsp;<b>Experte</b>&nbsp;FAQs hinterlassen (bspw. Kanzlei)</ccb-button
>
</a-link>
</a-stack>
</a-inline>
<a-stack size="md" class="${this.css({ alignItems: 'center' })}">
<ccb-h4>Unsere Partner:</ccb-h4>
<a-inline horizontal size="md" class="${this.css({ opacity: '0.6', justifyContent: 'center' })}">
<img
src="https://www.ksb-intax.de/typo3conf/ext/ksb_site/Resources/Public/images/logo-ksb-intax-blue-trans.png"
class="${this.css({ display: 'block', height: '50px' })}"
/>
<img
src="https://media-exp1.licdn.com/dms/image/C4D1BAQH04Fs5dnPoiw/company-background_10000/0?e=2159024400&v=beta&t=3DphZgZb6oRh9WDQuSK6VNnKt8U2YRsIqnaD-4bDhqk"
class="${this.css({ display: 'block', height: '50px' })}"
/>
<img
src="https://fps-law.de/files/themes/fps/images/fps-logo-de.gif"
class="${this.css({ display: 'block', height: '50px' })}"
/>
<img
src="https://weblaw.ch/.imaging/default/dam/weblaw/events/107/1078/10782/Weblaw-4farbig/jcr:content.jpg"
class="${this.css({ display: 'block', height: '50px' })}"
/>
<img
src="https://www.steuernundrecht.berlin/wp-content/uploads/2016/11/Logo_Endt-Eckhardt.png"
class="${this.css({ display: 'block', height: '50px' })}"
/>
</a-inline>
</a-stack>
</a-inline>
<img
src="/wirvsviruslogo.png"
class="${this.css({
marginLeft: 'auto',
marginRight: 'auto',
height: '100px',
width: 'auto',
display: 'block',
})}"
/>
</a-stack>
<img
src="/wirvsviruslogo.png"
class="${this.css({
marginLeft: 'auto',
marginRight: 'auto',
height: '100px',
width: 'auto',
display: 'block',
})}"
/>
</a-stack>
</a-box>
`;
case 'institutes':
return html`
......
......@@ -38,7 +38,7 @@ export class ccbTopbar extends EmotionMixin(ScopingElement) {
><mwc-icon>menu</mwc-icon></ccb-h3
>
</ccb-stack>
<a-link href="/"> <img src="/coronalogo.png" style="cursor: pointer; height: 50px;" /> </a-link>
<a-link href="/"> <img src="/coronalogo.png" style="cursor: pointer; height: 60px;" /> </a-link>
<ccb-h4 class="${this.css({ cursor: 'pointer', userSelect: 'none' })}" @click="${() => AdornisUser.logout()}"
>Logout</ccb-h4
>
......
......@@ -17,6 +17,7 @@ import './ccb-chat';
import './ccb-admin';
import './ccb-contents-admin';
import './ccb-landing-page';
import './ccb-content-view';
@element('main-element')
export class MainElement extends Loader(AdornisLayout) {
......@@ -60,7 +61,7 @@ export class MainElement extends Loader(AdornisLayout) {
><ccb-h4>Institutionen</ccb-h4></a-link
>
<a-link class="${this.css({ cursor: 'pointer' })}" href="/contentadmin"
><ccb-h4>Inhalt-Admin</ccb-h4></a-link
><ccb-h4>Inhalte hinzufügen</ccb-h4></a-link
>
<ccb-h4 class="${this.css({ cursor: 'pointer' })}" href="/datenschutz">Datenschutz</ccb-h4>
<ccb-h4
......@@ -109,7 +110,6 @@ export class MainElement extends Loader(AdornisLayout) {
: ''}
${combineLatest(AdornisRouter.get('page'), AdornisUser.currentUser).pipe(
map(([page, user]) => {
if (!user) return this.login();
switch (page) {
case '':
case 'institutes':
......@@ -117,10 +117,12 @@ export class MainElement extends Loader(AdornisLayout) {
<ccb-landing-page></ccb-landing-page>
`;
case 'admin':
if (!user) return this.login();
return html`
<ccb-admin></ccb-admin>
`;
case 'contentadmin':
if (!user) return this.login();
return html`
<ccb-contents-admin></ccb-contents-admin>
`;
......@@ -132,6 +134,10 @@ export class MainElement extends Loader(AdornisLayout) {
return html`
<ccb-landingpage></ccb-landingpage>
`;
case 'content':
return html`
<ccb-content-view></ccb-content-view>
`;
default:
return html`
404 - Not found
......@@ -166,13 +172,4 @@ export class MainElement extends Loader(AdornisLayout) {
AdornisUser.requestLogin(username, 'demoAccountPassword');
});
}
/*
Botbar entfernt, da ungeschickt für mobile. Inhalt der Botbar in leftSidebar verschoben
public botBar() {
return html`
<ccb-botbar></ccb-botbar>
`;
}*/
}
......@@ -9,6 +9,11 @@ import { AdornisFile, files } from '@adornis/file-utils/db';
if (isServer()) files._ensureIndex({ Rechtsgebiet: 'text', Frage: 'text', Antwort: 'text', Ansprechpartner: 'text' });
export enum Country {
GERMANY = 'Deutschland',
SWISS = 'Schweiz',
}
@Entity()
export class Rating extends AdornisEntity {
public static _name = 'Rating';
......@@ -42,7 +47,8 @@ export class Content extends AdornisFile {
public Quelle?: string;
@Field(String, {
preSaveHook: (fieldValue: any, fieldKey: string, entity: AdornisEntity) => {
return entity.crawlSource();
return fieldValue;
// return entity.crawlSource();
},
})
public crawlContent?: string;
......@@ -58,21 +64,35 @@ export class Content extends AdornisFile {
public updateAt!: Date;
@Field([Rating], { default: [] })
public ratings!: Rating[];
@Field(String)
public country?: Country;
public rate(positive: boolean) {
this.ratings.push(new Rating({ rating: positive }));
this.save();
}
public isRecent() {
//returns false when older than a week
const today = new Date();
if (today.getTime() - this.createdAt.getTime() > 60 * 60 * 1000 * 24 * 7) {
return false;
} else {
return true;
}
}
public crawlSource() {
if (!this.Quelle || !this.Quelle.length) return;
const request = require('request-promise-native');
return request(this.Quelle, { json: true })
.then(res => {
console.log(res);
return res;
})
.catch(err => console.log(err));
.catch(err => {
console.log(err);
return '';
});
}
}
Subproject commit ffb2da949538ebd0316522010551790933777b7a
Subproject commit 8a3cb167b61883f2893b40282e5da2708f81537c
......@@ -29,6 +29,22 @@ expressApp.post('/api/dialogflow-webhook', (request, response, next) => {
return;
}
if (agent.query === 'Kontakt aufnehmen') {
// TODO intent detection
agent.add(
'Du interessierst dich für Steuerrecht, wir haben einen passenden Partner aus unserem Netzwerk ausgesucht',
);
agent.add(
new Card({
title: 'Rechtsanwältin Mirella Endt-Eckhardt',
text: 'Tel. +4916094430671 \n Mail: mail@steuernundrecht.berlin',
buttonText: 'Website',
buttonUrl: 'https://www.steuernundrecht.berlin',
}),
);
return;
}
// answer to disclaimer
if (agent.contexts.find(el => el.name === 'asked-for-disclaimer')) {
if (agent.query === 'Ja') {
......@@ -91,27 +107,38 @@ expressApp.post('/api/dialogflow-webhook', (request, response, next) => {
return;
}
console.log('delivering content', content);
const antwortText = content.Antwort?.replace(/<[^>]*>/gi, '')
.replace(/[\s]+$|^[\s]+/g, '')
.replace(/&nbsp;/gi, '');
const slicedAntwort = antwortText.slice(0, 400);
agent.add(
new Card({
title: content.Frage || 'kein Titel',
// imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
text:
content.Antwort?.replace(/<[^>]*>/gi, '')
.replace(/[\s]+$|^[\s]+/g, '')
.replace(/&nbsp;/gi, '') + '.',
// // imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
text: slicedAntwort,
buttonText: 'Weiterführende Informationen',
buttonUrl: content.Quelle || 'https://google.com/',
buttonUrl: antwortText.length > 400 ? Meteor.absoluteUrl() + 'content/' + content._id : content.Quelle,
}),
);
const creator = (await AdornisUser.findOne({ _id: content.createdBy }).result) as CCBUser;
if (!!creator && !!creator.verified) {
agent.add('von ' + creator.contactName + ' (' + creator.contactMail + ', ' + creator.organization + ')');
agent.add(
'bereitgestellt von ' +
creator.contactName +
' (' +
creator.contactMail +
', ' +
creator.organization +
')',
);
} else {
agent.add('Diese Nachricht wurde aus automatisch generierten Inhalten erzeugt');
}
agent.add('Konnten wir dir damit weiterhelfen?');
agent.add(new Suggestion('Ja, danke!'));
agent.add(new Suggestion('noch einmal suchen'));
agent.add(new Suggestion('weiter suchen'));
agent.add(new Suggestion('Kontakt aufnehmen'));
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment