Merge pull request #74 from paoloar77/Booking_Events

Booking events
This commit is contained in:
Paolo Arena
2019-10-26 10:11:54 +02:00
committed by GitHub
46 changed files with 1494 additions and 397 deletions

View File

@@ -7,7 +7,7 @@ export const shared_consts = {
},
fieldsUserToChange() {
return ['username', 'email', 'name', 'surname', 'perm', 'date_reg', 'verified_email']
return ['username', 'email', 'name', 'surname', 'perm', 'date_reg', 'verified_email', 'img', 'ipaddr']
}
}

View File

@@ -29,6 +29,7 @@ import { static_data } from '@src/db/static_data'
import translate from '@src/globalroutines/util'
import { lists } from '../../store/Modules/lists'
import { GlobalStore } from '../../store/Modules'
import { IMessagePage, IMessage, IIdentity } from '../../model'
@Component({
name: 'CEventsCalendar',
@@ -58,6 +59,18 @@ export default class CEventsCalendar extends Vue {
modified: false
}
public formAskForDefault: IMessage = {
dest: {
idapp: process.env.APP_ID,
username: ''
},
origin: {
idapp: process.env.APP_ID,
username: ''
},
message: ''
}
public mioalert = false
public dateFormatter: any = ''
@@ -78,10 +91,16 @@ export default class CEventsCalendar extends Vue {
bookedevent: null,
state: EState.None
}
public askInfopage: IMessagePage = {
show: false,
msg: null,
state: EState.None
}
public contextDay = null
public eventForm: IEvents = { ...this.formDefault }
public bookEventForm = { ...this.formbookEventDefault }
public askInfoForm: IMessage = { ...this.formAskForDefault }
public displayEvent = false
public myevent = null
// public events = []
@@ -355,7 +374,6 @@ export default class CEventsCalendar extends Vue {
return this
}
public $refs: {
calendar: any
}
@@ -424,7 +442,7 @@ export default class CEventsCalendar extends Vue {
}
public addBookEventMenu(eventparam) {
if (!UserStore.state.isLogged || !UserStore.state.verified_email) {
if (!UserStore.state.isLogged || !UserStore.state.my.verified_email) {
// Visu right Toolbar to make SignIn
GlobalStore.state.RightDrawerOpen = true
// this.$router.push('/signin')
@@ -434,6 +452,7 @@ export default class CEventsCalendar extends Vue {
this.myevent = eventparam
this.bookEventForm.msgbooking = ''
this.bookEventForm.numpeople = 1
this.bookEventForm.booked = true
this.bookEventpage.state = EState.Creating
this.displayEvent = false
@@ -441,6 +460,28 @@ export default class CEventsCalendar extends Vue {
}
}
public askForInfoEventMenu(eventparam) {
if (!UserStore.state.isLogged || !UserStore.state.my.verified_email) {
// Visu right Toolbar to make SignIn
GlobalStore.state.RightDrawerOpen = true
// this.$router.push('/signin')
} else {
console.log('askForInfoEventMenu')
this.askInfoForm = { ...this.formAskForDefault }
this.myevent = eventparam
this.askInfoForm = {
message: ''
}
this.askInfopage.state = EState.Creating
this.displayEvent = false
this.askInfopage.show = true // show dialog
}
}
public clEvent(event: IEvents) {
return (this.isAlreadyBooked(event) ? 'text-left bg-light-green-1' : 'text-left')
}
@@ -460,10 +501,7 @@ export default class CEventsCalendar extends Vue {
}
public deleteEvent(eventparam) {
const index = this.findEventIndex(eventparam)
if (index >= 0) {
CalendarStore.state.eventlist.splice(index, 1)
}
tools.CancelEvent(this, eventparam)
}
public findEventIndex(eventparam) {
@@ -514,7 +552,7 @@ export default class CEventsCalendar extends Vue {
const mydatatosave = {
id: myrec._id,
table: 'myevents',
table: tools.TABEVENTS,
fieldsvalue: myrec
}
@@ -557,7 +595,7 @@ export default class CEventsCalendar extends Vue {
// ++Save into the Database
const mydatatosave = {
id: data._id,
table: 'myevents',
table: tools.TABEVENTS,
fieldsvalue: data
}
@@ -565,7 +603,7 @@ export default class CEventsCalendar extends Vue {
this.UpdateDbByFields(data, true)
} else {
const mydataadd = {
table: 'myevents',
table: tools.TABEVENTS,
data
}
@@ -623,7 +661,38 @@ export default class CEventsCalendar extends Vue {
}
public sendMsg(myevent: IEvents) {
// ..
const self = this
this.askInfopage.show = false
const data: IMessage = {
source: {
page: '',
event_id: myevent._id,
infoevent: tools.gettextevent(this, myevent)
},
idapp: process.env.APP_ID,
origin: {
idapp: process.env.APP_ID,
username: UserStore.state.username
},
dest: {
idapp: process.env.APP_ID,
username: myevent.teacher
},
read: false,
deleted: false,
message: this.askInfoForm.message,
datemsg: tools.getDateNow()
}
this.SendMsgEvent(data).then((ris) => {
self.contextDay = null
if (ris)
tools.showPositiveNotif(self.$q, self.$t('cal.sendmsg_sent'))
else
tools.showNegativeNotif(self.$q, self.$t('cal.sendmsg_error'))
})
}
public saveBookEvent(myevent: IEvents) {
@@ -638,7 +707,7 @@ export default class CEventsCalendar extends Vue {
// self.bookEventForm.booked = self.bookEventForm.bookedcheck
const data: IBookedEvent = {
userId: UserStore.state.userId,
userId: UserStore.state.my._id,
id_bookedevent: myevent._id,
numpeople: self.bookEventForm.numpeople,
infoevent: tools.gettextevent(self, myevent),
@@ -772,6 +841,10 @@ export default class CEventsCalendar extends Vue {
return await CalendarStore.actions.BookEvent(eventparam)
}
public async SendMsgEvent(param: IMessage) {
return await UserStore.actions.SendMsgEvent(param)
}
public isAlreadyBooked(eventparam: IEvents) {
return CalendarStore.getters.findEventBooked(eventparam, true)
}
@@ -961,6 +1034,8 @@ export default class CEventsCalendar extends Vue {
// check if event is in the past
const datenow = tools.addDays(tools.getDateNow(), -1)
return (myevent.dateTimeEnd >= datenow)
// console.log('datenow', datenow, 'end', myevent.dateTimeEnd)
return (new Date(myevent.dateTimeEnd) >= datenow)
}
}

View File

@@ -74,22 +74,8 @@
</q-chip>
</div>
<div v-if="myevent.dateTimeStart" class="cal__when">
<span class="cal__where-title">{{$t('cal.when')}}: </span>
<span class="cal__where-content">{{ tools.getstrDate(myevent.dateTimeStart)}} - {{ tools.getstrDate(myevent.dateTimeEnd)}}</span>
<span v-if="myevent.infoextra" class="cal__hours">
<span class="cal__hours-title">{{$t('cal.hours')}}: </span>
<span class="cal__hours-content">{{ myevent.infoextra }} </span>
</span>
<span v-else>
<span v-if="!tools.hasManyDays(myevent.dateTimeStart, myevent.dateTimeEnd)"
class="cal__hours">
-
<span class="cal__hours-title">{{$t('cal.hours')}}: </span>
<span class="cal__hours-content">{{$t('cal.starttime')}} {{ tools.getstrTime(myevent.dateTimeStart) }}
<span v-if="myevent.dateTimeEnd">{{ $t('cal.endtime')}}: {{ tools.getstrTime(myevent.dateTimeEnd) }}</span>
</span>
</span>
<span class="cal__where-title">{{$t('cal.when')}}:
<span v-html="tools.getstrDateTimeEvent(mythis, myevent, true)"></span>
</span>
</div>
<p v-if="myevent.linkpdf" style="margin-top: 10px; text-align: center">
@@ -307,28 +293,8 @@
{{myevent.title}}
</q-chip>
<div v-if="myevent.dateTimeStart" class="cal__when">
<span class="cal__where-title">{{$t('cal.when')}}: </span>
<span class="cal__where-content">{{func_tools.getDateStr(myevent.dateTimeStart)}}</span>
<span v-if="tools.hasManyDays(myevent.dateTimeStart)" class="cal__where-content"> - {{func_tools.getDateStr(myevent.dateTimeEnd)}}<br/></span>
<span v-if="myevent.infoextra" class="cal__hours">
<span class="cal__hours-title">{{$t('cal.hours')}}: </span>
<span class="cal__hours-content">{{ myevent.infoextra }} </span>
</span>
<span v-else>
<span v-if="!tools.hasManyDays(myevent.dateTimeStart, myevent.dateTimeEnd)"
class="cal__hours">
-
<span class="cal__hours-title">{{$t('cal.hours')}}: </span>
<span class="cal__hours-content"><span v-if="!tools.isMobile()">{{$t('cal.starttime')}} </span>{{ tools.getstrTime(myevent.dateTimeStart) }}
<span v-if="myevent.dateTimeEnd">
<span v-if="!tools.isMobile()">
{{$t('cal.endtime')}}
</span>
<span v-else> - </span>
{{ tools.getstrTime(myevent.dateTimeEnd) }}
</span>
</span>
</span>
<span class="cal__where-title">{{$t('cal.when')}}:
<span v-html="tools.getstrDateTimeEvent(mythis, myevent, true)"></span>
</span>
</div>
<div class="q-pa-xs">
@@ -369,7 +335,7 @@
<q-btn v-if="bookEventpage.state === EState.Modifying" flat :label="$t('cal.cancelbooking')"
color="negative"
@click="tools.CancelBookingEvent(mythis, myevent, bookEventForm._id, true)"></q-btn>
<q-btn v-if="checkseinviaMsg" flat :label="$t('dialog.sendmsg')" color="primary"
<q-btn v-if="checkseinviaMsg" flat :label="$t('dialog.sendonlymsg')" color="primary"
@click="sendMsg(myevent)"></q-btn>
<q-btn v-else flat :label="getTitleBtnBooking" color="primary" @click="saveBookEvent(myevent)"
:disable="!(bookEventpage.state === EState.Creating || hasModifiedBooking)"></q-btn>
@@ -380,6 +346,53 @@
</q-card>
</q-dialog>
<q-dialog v-model="askInfopage.show" no-backdrop-dismiss>
<q-card v-if="askInfopage.show" :style="`min-width: `+ tools.myheight_dialog() + `px;`">
<q-toolbar class="bg-primary text-white">
<q-toolbar-title>
{{$t('cal.booking')}}
</q-toolbar-title>
<q-btn flat round color="white" icon="close" v-close-popup></q-btn>
</q-toolbar>
<q-card-section class="inset-shadow">
<q-img :src="getImgEvent(myevent)"
class="absolute-top"
style="height: 150px;">
</q-img>
<div style="margin-top: 150px;">
<q-chip
:style="`background-color: ${myevent.bgcolor} !important; color: white !important;`"
text-color="white"
class="shadow-5 q-mb-md" dense>
{{myevent.title}}
</q-chip>
<div v-if="myevent.dateTimeStart" class="cal__when">
<span class="cal__where-title">{{$t('cal.when')}}:
<span v-html="tools.getstrDateTimeEvent(mythis, myevent, true)"></span>
</span>
</div>
<div class="q-pa-xs">
<q-card class="text-white windowcol">
<q-card-section>
<q-input v-model="askInfoForm.message" :label="$t('cal.msgbooking')+':'"
autogrow>
</q-input>
</q-card-section>
</q-card>
</div>
</div>
</q-card-section>
<q-card-actions align="right">
<q-btn flat :label="$t('dialog.sendmsg')" color="primary"
@click="sendMsg(myevent)"></q-btn>
<q-btn flat :label="$t('dialog.cancel')" color="primary" v-close-popup></q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<!--v-touch-swipe.mouse.left.right="handleSwipe" -->
<!-- the calendar -->
@@ -547,17 +560,7 @@
</p>
<div class="listaev__date listaev__align_center_mobile">
<div v-if="event.infoextra">
<span class="listaev__date">{{func_tools.getDateStr(event.dateTimeStart)}} - <span
class="cal__hours-content">{{ event.infoextra }}</span> </span>
</div>
<div v-else>
<div v-if="event.dateTimeStart" class="listaev__date">
{{tools.getstrDateTime(event.dateTimeStart)}} -
{{tools.getstrDateTime(event.dateTimeEnd)}}
</div>
</div>
<span v-html="tools.getstrDateTimeEvent(mythis, event, true)"></span>
</div>
<div class="listaev__align_center_mobile">
@@ -649,12 +652,16 @@
</span>
</p>
<div class="row justify-end">
<q-btn rounded outline
<q-btn rounded outline class="q-mx-sm"
color="primary" @click="askForInfoEventMenu(event)"
:label="$t('event.askinfo')">
</q-btn>
<q-btn rounded outline class="q-mx-sm"
v-if="!event.nobookable && !isAlreadyBooked(event) && static_data.functionality.BOOKING_EVENTS"
color="primary" @click="addBookEventMenu(event)"
:label="$t('cal.booking')" :disable="!isEventEnabled(event)">
</q-btn>
<q-btn rounded outline
<q-btn rounded outline class="q-mx-sm"
v-if="!event.nobookable && isAlreadyBooked(event) && static_data.functionality.BOOKING_EVENTS"
text-color="red"
@click.native="EditBookEvent(event)"

View File

@@ -0,0 +1,4 @@
.myflex{
display: flex;
flex: 1;
}

View File

@@ -0,0 +1,240 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { QEditor } from 'quasar'
@Component({
name: 'CMyEditor'
})
export default class CMyEditor extends Vue {
public $q
public editor = null
@Prop({ required: true }) public value
@Prop({ required: false, default: '' }) public myclass
public myvalue = ''
public mycolor = ''
public myfonts = {
arial: 'Arial',
arial_black: 'Arial Black',
comic_sans: 'Comic Sans MS',
courier_new: 'Courier New',
impact: 'Impact',
lucida_grande: 'Lucida Grande',
times_new_roman: 'Times New Roman',
verdana: 'Verdana'
}
public toolbarcomp = [
['left', 'center', 'right', 'justify'],
['bold', 'italic', 'underline', 'strike'],
[
{
label: this.$q.lang.editor.formatting,
icon: this.$q.iconSet.editor.formatting,
list: 'no-icons',
options: [
'p',
'h4',
'h5',
'h6',
'code'
]
},
{
label: this.$q.lang.editor.fontSize,
icon: this.$q.iconSet.editor.fontSize,
fixedLabel: true,
fixedIcon: true,
list: 'no-icons',
options: [
'size-1',
'size-2',
'size-3',
'size-4',
'size-5',
'size-6',
'size-7'
]
},
{
label: this.$q.lang.editor.defaultFont,
icon: this.$q.iconSet.editor.font,
fixedIcon: true,
list: 'no-icons',
options: [
'default_font',
'arial',
'arial_black',
'comic_sans',
'courier_new',
'impact',
'lucida_grande',
'times_new_roman',
'verdana'
]
},
'removeFormat'
],
['quote', 'unordered', 'ordered', 'outdent', 'indent'],
['undo', 'redo', 'viewsource'],
]
get tools() {
return tools
}
public changeval(newval) {
// console.log('changeval', newval)
this.$emit('update:value', newval)
}
public mounted() {
this.myvalue = this.value
this.editor = this.$refs.editor_ref
}
public setcolor() {
document.execCommand('foreColor', false, this.mycolor)
}
/**
* Capture the <CTL-V> paste event, only allow plain-text, no images.
*
* see: https://stackoverflow.com/a/28213320
*
* @param {object} evt - array of files
* @author Daniel Thompson-Yvetot
* @license MIT
*/
public pasteCapture(evt) {
// let text, onPasteStripFormattingIEPaste
// evt.preventDefault()
// if (evt.originalEvent && evt.originalEvent.clipboardData.getData) {
// text = evt.originalEvent.clipboardData.getData('text/plain')
// this.$refs.editor_ref.runCmd('insertText', text)
// }
// else if (evt.clipboardData && evt.clipboardData.getData) {
// text = evt.clipboardData.getData('text/plain')
// this.$refs.editor_ref.runCmd('insertText', text)
// }
// else if (window.clipboardData && window.clipboardData.getData) {
// if (!onPasteStripFormattingIEPaste) {
// onPasteStripFormattingIEPaste = true
// this.$refs.editor_ref.runCmd('ms-pasteTextOnly', text)
// }
// onPasteStripFormattingIEPaste = false
// }
}
}
/*
https://developer.mozilla.org/en-US/docs/Web/API/document/execCommand#Commands
backColor
Changes the document background color. In styleWithCss mode, it affects the background color of the containing block instead. This requires a <color> value string to be passed in as a value argument. Note that Internet Explorer uses this to set the text background color.
bold
Toggles bold on/off for the selection or at the insertion point. Internet Explorer uses the <strong> tag instead of <b>.
ClearAuthenticationCache
Clears all authentication credentials from the cache.
contentReadOnly
Makes the content document either read-only or editable. This requires a boolean true/false as the value argument. (Not supported by Internet Explorer.)
copy
Copies the current selection to the clipboard. Conditions of having this behavior enabled vary from one browser to another, and have evolved over time. Check the compatibility table to determine if you can use it in your case.
createLink
Creates an hyperlink from the selection, but only if there is a selection. Requires a URI string as a value argument for the hyperlink's href. The URI must contain at least a single character, which may be whitespace. (Internet Explorer will create a link with a null value.)
cut
Removes the current selection and copies it to the clipboard. When this behavior is enabled varies between browsers, and its conditions have evolved over time. Check the compatibility table for usage details.
decreaseFontSize
Adds a <small> tag around the selection or at the insertion point. (Not supported by Internet Explorer.)
defaultParagraphSeparator
Changes the paragraph separator used when new paragraphs are created in editable text regions. See Differences in markup generation for more details.
delete
Deletes the current selection.
enableAbsolutePositionEditor
Enables or disables the grabber that allows absolutely-positioned elements to be moved around. This is disabled by default in Firefox 63 Beta/Dev Edition (bug 1449564)
enableInlineTableEditing
Enables or disables the table row/column insertion and deletion controls. This is disabled by default in Firefox 63 Beta/Dev Edition (bug 1449564).
enableObjectResizing
Enables or disables the resize handles on images, tables, and absolutely-positioned elements and other resizable objects. This is disabled by default in Firefox 63 Beta/Dev Edition (bug 1449564).
fontName
Changes the font name for the selection or at the insertion point. This requires a font name string (like "Arial") as a value argument.
fontSize
Changes the font size for the selection or at the insertion point. This requires an integer from 1-7 as a value argument.
foreColor
Changes a font color for the selection or at the insertion point. This requires a hexadecimal color value string as a value argument.
formatBlock
Adds an HTML block-level element around the line containing the current selection, replacing the block element containing the line if one exists (in Firefox, <blockquote> is the exception — it will wrap any containing block element). Requires a tag-name string as a value argument. Virtually all block-level elements can be used. (Internet Explorer and Edge support only heading tags H1H6, ADDRESS, and PRE, which must be wrapped in angle brackets, such as "<H1>".)
forwardDelete
Deletes the character ahead of the cursor's position, identical to hitting the Delete key on a Windows keyboard.
heading
Adds a heading element around a selection or insertion point line. Requires the tag-name string as a value argument (i.e. "H1", "H6"). (Not supported by Internet Explorer and Safari.)
hiliteColor
Changes the background color for the selection or at the insertion point. Requires a color value string as a value argument. useCSS must be true for this to function. (Not supported by Internet Explorer.)
increaseFontSize
Adds a <big> tag around the selection or at the insertion point. (Not supported by Internet Explorer.)
indent
Indents the line containing the selection or insertion point. In Firefox, if the selection spans multiple lines at different levels of indentation, only the least indented lines in the selection will be indented.
insertBrOnReturn
Controls whether the Enter key inserts a <br> element, or splits the current block element into two. (Not supported by Internet Explorer.)
insertHorizontalRule
Inserts a <hr> element at the insertion point, or replaces the selection with it.
insertHTML
Inserts an HTML string at the insertion point (deletes selection). Requires a valid HTML string as a value argument. (Not supported by Internet Explorer.)
insertImage
Inserts an image at the insertion point (deletes selection). Requires a URL string for the image's src as a value argument. The requirements for this string are the same as createLink.
insertOrderedList
Creates a numbered ordered list for the selection or at the insertion point.
insertUnorderedList
Creates a bulleted unordered list for the selection or at the insertion point.
insertParagraph
Inserts a paragraph around the selection or the current line. (Internet Explorer inserts a paragraph at the insertion point and deletes the selection.)
insertText
Inserts the given plain text at the insertion point (deletes selection).
italic
Toggles italics on/off for the selection or at the insertion point. (Internet Explorer uses the <em> element instead of <i>.)
justifyCenter
Centers the selection or insertion point.
justifyFull
Justifies the selection or insertion point.
justifyLeft
Justifies the selection or insertion point to the left.
justifyRight
Right-justifies the selection or the insertion point.
outdent
Outdents the line containing the selection or insertion point.
paste
Pastes the clipboard contents at the insertion point (replaces current selection). Disabled for web content. See [1].
redo
Redoes the previous undo command.
removeFormat
Removes all formatting from the current selection.
selectAll
Selects all of the content of the editable region.
strikeThrough
Toggles strikethrough on/off for the selection or at the insertion point.
subscript
Toggles subscript on/off for the selection or at the insertion point.
superscript
Toggles superscript on/off for the selection or at the insertion point.
underline
Toggles underline on/off for the selection or at the insertion point.
undo
Undoes the last executed command.
unlink
Removes the anchor element from a selected hyperlink.
useCSS
Toggles the use of HTML tags or CSS for the generated markup. Requires a boolean true/false as a value argument.
NOTE: This argument is logically backwards (i.e. use false to use CSS, true to use HTML) and unsupported by Internet Explorer. This has been deprecated in favor of styleWithCSS.
styleWithCSS
Replaces the useCSS command. true modifies/generates style attributes in markup, false generates presentational elements.
*/

View File

@@ -0,0 +1,36 @@
<template>
<div>
<form
autocorrect="off"
autocapitalize="off"
autocomplete="off"
spellcheck="false">
<q-btn rounded size="sm" color="primary">
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy>
<q-color v-model="mycolor" @change="setcolor"></q-color>
</q-popup-proxy>
</q-icon>
</q-btn>
<q-editor
ref="editor_ref"
toolbar-text-color="white"
toolbar-toggle-color="yellow-8"
toolbar-bg="primary"
:toolbar="toolbarcomp"
:fonts="myfonts"
@input="changeval"
@paste.native="evt => pasteCapture(evt)"
v-model="myvalue">
</q-editor>
</form>
</div>
</template>
<script lang="ts" src="./CMyEditor.ts">
</script>
<style lang="scss" scoped>
@import './CMyEditor.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CMyEditor} from './CMyEditor.vue'

View File

@@ -0,0 +1,4 @@
.myflex{
display: flex;
flex: 1;
}

View File

@@ -0,0 +1,56 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { IPerson } from '../../model/GlobalStore'
@Component({
name: 'CMySelect'
})
export default class CMySelect extends Vue {
@Prop({ required: true }) public value
@Prop({ required: true, default: '' }) public label
@Prop({ required: false, default: '' }) public myclass
@Prop({ required: true, default: '' }) public optlab
@Prop({ required: true, default: '' }) public optval
@Prop({ required: false, default: true }) public useinput: boolean
@Prop({ required: false, default: null }) public newvaluefunc
@Prop({ required: false, default: null }) public funcgetvaluebyid
@Prop({ required: true }) public options
public myvalue = ''
get tools() {
return tools
}
public nothing() {
}
public changeval(newval) {
console.log('changeval', newval)
// const newvallab = newval[`${this.optval}`]
// this.myvalue = newvallab
this.$emit('update:value', newval)
}
public mounted() {
const rec = this.options.find((myrec) => myrec[`${this.optval}`] === this.value)
console.log('rec', rec)
if (!this.useinput) {
this.myvalue = this.value
} else {
if (rec) {
if (this.funcgetvaluebyid)
this.myvalue = this.funcgetvaluebyid(rec[`${this.optval}`])
else
this.myvalue = rec[`${this.optlab}`]
console.log('this.myvalue', this.myvalue, 'this.optval', this.optval, 'rec', rec[`${this.optval}`])
}
}
}
}

View File

@@ -0,0 +1,46 @@
<template>
<div>
<div v-if="useinput">
<q-select
:input-class="myclass"
filled
v-model="myvalue"
:use-input="useinput"
input-debounce="0"
@new-value="newvaluefunc"
new-value-mode="add-unique"
:options="options"
:option-value="optval"
:option-label="optlab"
@input="changeval"
:label="label"
dense
>
</q-select>
</div>
<div v-else>
<q-select
:input-class="myclass"
filled
v-model="myvalue"
:options="options"
:option-value="optval"
:option-label="optlab"
@input="changeval"
:label="label"
emit-value
map-options
style="min-width: 170px; max-width: 400px;"
>
</q-select>
</div>
</div>
</template>
<script lang="ts" src="./CMySelect.ts">
</script>
<style lang="scss" scoped>
@import './CMySelect.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CMySelect} from './CMySelect.vue'

View File

@@ -4,7 +4,7 @@ import { UserStore } from '@store'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { ISignupOptions, IUserState } from 'model'
import { ISignupOptions, IUserState, IUserFields } from 'model'
import { validations, TSignup } from './CSignUp-validate'
import { validationMixin } from 'vuelidate'

View File

@@ -211,7 +211,7 @@ canvas {
}
.toolbar {
min-height: 30px;
min-height: 43px;
}
.right-itens a, .right-itens button {
@@ -296,3 +296,8 @@ canvas {
margin-bottom: 5px;
}
.roundimg {
border-radius: 50% !important;
color: red;
background-color: red;
}

View File

@@ -15,8 +15,11 @@ import Quasar, { Screen } from 'quasar'
import { static_data } from '../../db/static_data'
import globalroutines from '../../globalroutines'
import MixinUsers from '../../mixins/mixin-users'
@Component({
name: 'Header',
mixins: [MixinUsers],
components: {
drawer,
messagePopover, CSignIn
@@ -40,10 +43,6 @@ export default class Header extends Vue {
public photo = ''
public visuimg: boolean = true
get tools() {
return tools
}
get conn_changed() {
return GlobalStore.state.stateConnection
}
@@ -315,28 +314,6 @@ export default class Header extends Vue {
}, 100)
}
get MenuCollapse() {
return GlobalStore.state.menuCollapse
// return true
}
get Username() {
return UserStore.state.username
}
get myName() {
return UserStore.state.name
}
get mySurname() {
return UserStore.state.surname
}
get Verificato() {
return UserStore.state.verified_email
}
get Email() {
return UserStore.state.email
}
public logoutHandler() {
UserStore.actions.logout()
.then(() => {
@@ -359,7 +336,7 @@ export default class Header extends Vue {
}
get isVerified() {
return UserStore.state.verified_email
return UserStore.state.my.verified_email
}
public loginOk() {

View File

@@ -93,9 +93,7 @@
</q-btn-dropdown>
<!--
<message-popover></message-popover>
-->
<!--
<div class="right-itens">
@@ -104,11 +102,14 @@
<!-- BUTTON USER BAR -->
<q-btn v-if="static_data.functionality.SHOW_USER_MENU && !isLogged" dense flat round icon="menu"
<q-btn class="q-mx-xs" v-if="static_data.functionality.SHOW_USER_MENU && !isLogged" dense flat round icon="menu"
@click="rightDrawerOpen = !rightDrawerOpen">
</q-btn>
<q-btn v-if="static_data.functionality.SHOW_USER_MENU && isLogged" dense flat round
icon="img:statics/images/avatar/avatar3_small.png" @click="rightDrawerOpen = !rightDrawerOpen">
<q-btn class="q-mx-xs" v-if="static_data.functionality.SHOW_USER_MENU && isLogged" round dense flat
@click="rightDrawerOpen = !rightDrawerOpen">
<q-avatar size="30px">
<img :src="getMyImg">
</q-avatar>
</q-btn>
</q-toolbar>
@@ -136,7 +137,7 @@
<div class="absolute-top bg-transparent text-black center_img" style="margin-top: 10px;">
<q-avatar class="q-mb-sm center_img">
<img src="../../statics/images/avatar/avatar3_small.png">
<img :src="`../../` + getMyImg">
</q-avatar>
<q-btn class="absolute-top-right" style="margin-right: 10px; color: white;"
dense flat round icon="close" @click="rightDrawerOpen = !rightDrawerOpen">

View File

@@ -0,0 +1,32 @@
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
import { SingleProject } from '../../projects/SingleProject'
import { CTodo } from '../../todos/CTodo'
import { GlobalStore } from '../../../store/Modules'
@Component({})
export default class CTesseraElettronica extends Vue {
public $q
public $t
public $refs: {
frametessera
}
public mounted() {
// ...
// $('#frametessera').contents().find('#nome').val("PPPP")
}
get getNome() {
return ''
}
get getFrame() {
// console.log('getFrame', $('#frametessera'))
return ''
}
get rightDrawerOpen() {
return GlobalStore.state.RightDrawerOpen
}
}

View File

@@ -0,0 +1,22 @@
<template>
<q-card class="q-ma-xs" bordered>
<q-card-section>
<div class="text-h6 bg-deep-purple-8 text-white text-center">Per accedere alla Tessera:
</div>
</q-card-section>
<q-separator inset/>
<q-card-section>
<iframe v-if="rightDrawerOpen" id="frametessera" ref="frametessera"
src="https://www.conceptstudio.it/website/csenravenna/electro/"
style="border: 0; width: 100%; max-width: 360px; min-height: 500px;"></iframe>
</q-card-section>
<!--Elisa GHZLSE78A65G388B-->
</q-card>
</template>
<script lang="ts" src="./CTesseraElettronica.ts">
</script>
<style lang="scss" scoped>
@import './CTesseraElettronica.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CTesseraElettronica} from './CTesseraElettronica.vue'

View File

@@ -293,7 +293,7 @@ export default class SingleProject extends Vue {
}
get isMyProject() {
return this.itemproject.userId === UserStore.state.userId
return this.itemproject.userId === UserStore.state.my._id
}
get tipoProj() {

View File

@@ -15,7 +15,7 @@ function saveConfigIndexDb(context) {
_id: costanti.CONFIG_ID_CFG,
lang: toolsext.getLocale(),
token: UserStore.state.x_auth_token,
userId: UserStore.state.userId
userId: UserStore.state.my._id
}
writeConfigIndexDb('config', data)

View File

@@ -1,35 +1,46 @@
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
import { GlobalStore } from '@store'
import { IPost } from '../../../model/index'
import { GlobalStore, CalendarStore } from '@store'
import { ICalendarState, IMessage, IPost, IUserState } from '../../../model/index'
import './messagePopover.scss'
import { tools } from '@src/store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { ITodo, ITodosState } from '../../../model'
import { Getter } from 'vuex-class'
import { UserStore } from '../../../store/Modules'
import MixinUsers from '../../../mixins/mixin-users'
const namespace = 'MessageModule'
@Component({
mixins: [MixinUsers]
})
export default class MessagePopover extends Vue {
posts: IPost[] = []
@Getter('getlasts_messages', { namespace })
public lasts_messages: (state: IUserState) => IMessage[]
public created() {
if (GlobalStore.state.posts.length < 1) {
this.requestPosts()
}
// if (GlobalStore.state.posts.length < 1) {
// this.requestPosts()
// }
}
get filteredPosts() {
if (this.posts.length >= 1)
return this.posts.slice(0, 5)
else
return []
public clickChat(msg: IMessage){
this.$router.replace('/messages/' + msg.dest.username)
}
get getNumNotifUnread() {
return 0
}
public randomDate(): Date {
let myval = Math.floor(Math.random() * 10000000000)
return new Date(tools.getTimestampsNow() - myval)
const myval = Math.floor(Math.random() * 10000000000)
return tools.getstrDateTime(new Date(tools.getTimestampsNow() - myval))
}
public randomAvatarUrl() {
@@ -63,10 +74,10 @@ export default class MessagePopover extends Vue {
*/
}
public requestPosts() {
// console.log('requestPosts...')
let prova = [{ title: 'primo' }, { title: 'Secondo' }]
this.posts.push(...prova)
}
// public requestPosts() {
// // console.log('requestPosts...')
// let prova = [{ title: 'primo' }, { title: 'Secondo' }]
// this.posts.push(...prova)
//
// }
}

View File

@@ -1,25 +1,48 @@
<template>
<button class="relative-position animate-bounce">
<i class="fa fa-2x fa-envelope-o"></i>
<span class="floating label bg-dark">5</span>
<div>
<q-btn flat round dense icon="fas fa-comment" class="q-mx-xs" >
<q-badge floating color="red">{{getNumMsgUnread}}</q-badge>
<q-menu self="top right">
<div class="list striped">
<p class="caption no-margin text-center text-white bg-teal">Messages from people</p>
<div class="item item-link two-lines item-delimiter no-margin"
v-for="post in filteredPosts"
>
<img class="item-primary" :src="randomAvatarUrl()">
<div class="item-content has-secondary">
<div>{{post.title}}</div>
<div>{{randomDate()}}</div>
</div>
<span class="label bg-red text-white item-secondary no-margin">
<i class="left-detail"></i> New
</span>
</div>
<q-list bordered class="rounded-borders" style="max-width: 350px; min-width: 250px;">
<q-item-label header>{{$t('msgs.messages')}}</q-item-label>
<q-separator/>
<div v-if="getNumMsg === 0">
<q-item>
{{$t('msgs.nomessage')}}
</q-item>
</div>
<q-item clickable v-ripple v-for="(msg, index) in lasts_messages()" :key="index" @click="clickChat(msg)">
<q-item-section avatar>
<q-avatar>
<img :src="getImgByUsername(msg.dest.username)">
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label lines="1">{{getUserByUsername(msg.dest.username)}}</q-item-label>
<q-item-label caption lines="2">
{{msg.message}}
</q-item-label>
</q-item-section>
<q-item-section side top>
{{tools.getstrDateTimeShort(msg.datemsg)}}
</q-item-section>
</q-item>
<q-separator/>
</q-list>
</q-menu>
</button>
</q-btn>
<q-btn v-if="false" flat round dense icon="fas fa-bell">
<q-badge v-if="getNumNotifUnread > 0" floating color="red">{{getNumNotifUnread}}</q-badge>
</q-btn>
</div>
</template>
<script lang="ts" src="./messagePopover.ts">

61
src/mixins/mixin-users.ts Normal file
View File

@@ -0,0 +1,61 @@
import Vue from 'vue'
import { GlobalStore, UserStore, MessageStore } from '../store/Modules'
import Component from 'vue-class-component'
import { func_tools } from '../store/Modules/toolsext'
import { tools } from '../store/Modules/tools'
// You can declare a mixin as the same style as components.
@Component
export default class MixinUsers extends Vue {
public mythis() {
return this
}
get func_tools() {
return func_tools
}
get tools() {
return tools
}
public getUserByUsername(username) {
return UserStore.getters.getNameSurnameByUsername(username)
}
public getImgByUsername(username) {
return `statics/` + UserStore.getters.getImgByUsername(username)
}
public getMyUsername() {
return UserStore.state.my.username
}
get getMyImg() {
return 'statics/' + UserStore.getters.getImgByUsername(UserStore.state.my.username)
}
get MenuCollapse() {
return GlobalStore.state.menuCollapse
// return true
}
get Username() {
return UserStore.state.my.username
}
get myName() {
return UserStore.state.my.name
}
get mySurname() {
return UserStore.state.my.surname
}
get Verificato() {
return UserStore.state.my.verified_email
}
get Email() {
return UserStore.state.my.email
}
get getNumMsg() {
return MessageStore.getters.getlasts_messages().length
}
get getNumMsgUnread() {
// return UserStore.getters.getlasts_messages().length
return MessageStore.getters.getnumMsgUnread()
}
}

View File

@@ -78,6 +78,7 @@ export interface IBookedEventPage {
state: EState
}
export interface ICalendarState {
editable: boolean
eventlist: IEvents[]

View File

@@ -1,29 +1,37 @@
import { IToken } from 'model/other'
export const DefaultUser = <IUserState>{
export const DefaultUser: IUserFields = {
email: '',
username: '',
name: '',
surname: '',
password: '',
lang: 'it'
password: ''
}
export interface IUserState {
userId?: string
export interface IUserFields {
_id?: string
email?: string
username?: string
name?: string
surname?: string
password?: string
lang?: string
ipaddr?: string
perm?: number
img?: string
verified_email?: boolean
tokens?: IToken[]
}
/*
password?: string
lang
*/
export interface IUserState {
my: IUserFields
lang?: string
repeatPassword?: string
tokens?: IToken[]
verified_email?: boolean
categorySel?: string
tokenforgot?: string
@@ -34,13 +42,6 @@ export interface IUserState {
isLogged?: boolean
isAdmin?: boolean
isManager?: boolean
usersList?: IUserList[]
usersList?: IUserFields[]
countusers?: number
}
export interface IUserList {
_id: string
username: string
name?: string
surname?: string
}

View File

@@ -1,4 +1,5 @@
export * from './UserStore'
export * from './MessageStore'
export * from './GlobalStore'
export * from './signin-option'
export * from './signup-option'

View File

@@ -18,6 +18,9 @@ const msgglobal = {
},
manage: {
menu: 'Gestione'
},
messages: {
menu: 'I tuoi Messaggi'
}
},
sendmsg: {
@@ -33,7 +36,8 @@ const msgglobal = {
add: 'Aggiungi',
today: 'Oggi',
book: 'Prenota',
sendmsg: 'Invia solo un Msg',
sendmsg: 'Invia Messaggio',
sendonlymsg: 'Invia solo un Msg',
msg: {
titledeleteTask: 'Elimina Task',
deleteTask: "Vuoi Eliminare {mytodo}?"
@@ -84,7 +88,7 @@ const msgglobal = {
richiesto: 'Campo Richiesto',
email: 'Email',
cell: 'Móvil',
img: 'Imagen de archivo',
img: 'Immagine',
date_reg: 'Data Reg.',
perm: 'Permessi',
username: 'Nome Utente',
@@ -194,14 +198,20 @@ const msgglobal = {
cal: {
booked: 'Prenotato',
booked_error: 'Prenotazione non avvenuta. Riprovare più tardi',
sendmsg_error: 'Messaggio non inviato. Riprovare più tardi',
sendmsg_sent: 'Messaggio Inviato',
booking: 'Prenota Evento',
titlebooking: 'Prenotazione',
modifybooking: 'Modifica Prenotazione',
cancelbooking: 'Cancella Prenotazione',
canceledbooking: 'Prenotazione Cancellata',
cancelederrorbooking: 'Cancellazione non effettuata, Riprovare più tardi',
cancelevent: 'Cancella Evento',
canceledevent: 'Evento Cancellato',
cancelederrorevent: 'Cancellazione Evento non effettuata, Riprovare',
event: 'Evento',
starttime: 'Dalle',
enddate: 'al',
endtime: 'alle',
duration: 'Durata',
hours: 'Orario',
@@ -224,6 +234,11 @@ const msgglobal = {
teachertitle: 'Insegnante',
peoplebooked: 'Prenotaz.',
},
msgs: {
message: 'Messaggio',
messages: 'Messaggi',
nomessage: 'Nessun Messaggio'
},
event: {
_id: 'id',
typol: 'Typology',
@@ -288,6 +303,9 @@ const msgglobal = {
},
manage: {
menu: 'Gestionar'
},
messages: {
menu: 'Tus mensajes'
}
},
sendmsg: {
@@ -303,7 +321,8 @@ const msgglobal = {
add: 'Aggrega',
today: 'Hoy',
book: 'Reserva',
sendmsg: 'Envia solo Mensaje',
sendmsg: 'Envia Mensaje',
sendonlymsg: 'Envia solo Mensaje',
msg: {
titledeleteTask: 'Borrar Tarea',
deleteTask: 'Quieres borrar {mytodo}?'
@@ -458,6 +477,8 @@ const msgglobal = {
cal: {
booked: 'Reservado',
booked_error: 'Reserva fallida. Intenta nuevamente más tarde',
sendmsg_error: 'Mensaje no enviado Intenta nuevamente más tarde',
sendmsg_sent: 'Mensaje enviado',
booking: 'Reserva Evento',
titlebooking: 'Reserva',
modifybooking: 'Edita Reserva',
@@ -466,6 +487,7 @@ const msgglobal = {
cancelederrorbooking: 'Cancelación no realizada, intente nuevamente más tarde',
event: 'Evento',
starttime: 'Inicio',
enddate: 'a',
endtime: 'fin',
duration: 'Duración',
hours: 'Tiempo',
@@ -488,6 +510,11 @@ const msgglobal = {
teachertitle: 'Maestro',
peoplebooked: 'Reserv.',
},
msgs: {
message: 'Mensaje',
messages: 'Mensajes',
nomessage: 'Sin Mensaje'
},
event: {
_id: 'id',
typol: 'Typology',
@@ -552,6 +579,9 @@ const msgglobal = {
},
manage: {
menu: 'Gérer'
},
messages: {
menu: 'Vos messages'
}
},
sendmsg: {
@@ -567,7 +597,8 @@ const msgglobal = {
cancel: 'annuler',
today: 'Aujourd\'hui',
book: 'Réserve',
sendmsg: 'envoyer seul un msg',
sendmsg: 'envoyer msg',
sendonlymsg: 'envoyer seul un msg',
msg: {
titledeleteTask: 'Supprimer la tâche',
deleteTask: 'Voulez-vous supprimer {mytodo}?'
@@ -721,6 +752,8 @@ const msgglobal = {
cal: {
booked: 'Réservé',
booked_error: 'La réservation a échoué. Réessayez plus tard',
sendmsg_error: 'Message non envoyé. Réessayez plus tard',
sendmsg_sent: 'Message envoyé',
booking: 'Réserver l\'événement',
titlebooking: 'Réservation',
modifybooking: 'changement de réservation',
@@ -729,6 +762,7 @@ const msgglobal = {
cancelederrorbooking: 'Annulation non effectuée, réessayez plus tard',
event: 'événement',
starttime: 'Accueil',
enddate: 'au',
endtime: 'fin',
duration: 'Durée',
hours: 'Le temps',
@@ -751,6 +785,11 @@ const msgglobal = {
teachertitle: 'Professeur',
peoplebooked: 'Réserv.',
},
msgs: {
message: 'Message',
messages: 'Messages',
nomessage: 'Pas de message'
},
event: {
_id: 'id',
typol: 'Typologie',
@@ -815,6 +854,9 @@ const msgglobal = {
},
manage: {
menu: 'Manage'
},
messages: {
menu: 'Your Messages'
}
},
sendmsg: {
@@ -830,7 +872,8 @@ const msgglobal = {
cancel: 'Cancel',
today: 'Today',
book: 'Book',
sendmsg: 'Send only a Msg',
sendmsg: 'Send Message',
sendonlymsg: 'Send only a Msg',
msg: {
titledeleteTask: 'Delete Task',
deleteTask: 'Delete Task {mytodo}?'
@@ -983,6 +1026,8 @@ const msgglobal = {
cal: {
booked: 'Booked',
booked_error: 'Reservation failed. Try again later',
sendmsg_error: 'Message not sent. Try again later',
sendmsg_sent: 'Message sent',
booking: 'Book the Event',
titlebooking: 'Reservation',
modifybooking: 'Modify Reservation',
@@ -991,6 +1036,7 @@ const msgglobal = {
cancelederrorbooking: 'Cancellation unsuccessfully, try again later',
event: 'Event',
starttime: 'From',
enddate: 'to',
endtime: 'to',
duration: 'Duration',
hours: 'Hours',
@@ -1013,6 +1059,11 @@ const msgglobal = {
teachertitle: 'Teacher',
peoplebooked: 'Booked',
},
msgs: {
message: 'Messaggio',
messages: 'Messaggi',
nomessage: 'Nessun Messaggio'
},
event: {
_id: 'id',
typol: 'Typology',
@@ -1077,6 +1128,9 @@ const msgglobal = {
},
manage: {
menu: 'Manage'
},
messages: {
menu: 'Your Messages'
}
},
sendmsg: {
@@ -1092,7 +1146,8 @@ const msgglobal = {
cancel: 'Cancel',
today: 'Today',
book: 'Book',
sendmsg: 'Send only a Msg',
sendmsg: 'Send Message',
sendonlymsg: 'Send only a Msg',
msg: {
titledeleteTask: 'Delete Task',
deleteTask: 'Delete Task {mytodo}?'
@@ -1247,6 +1302,8 @@ const msgglobal = {
cal: {
booked: 'Booked',
booked_error: 'Reservation failed. Try again later',
sendmsg_error: 'Message not sent. Try again later',
sendmsg_sent: 'Message sent',
booking: 'Book the Event',
titlebooking: 'Reservation',
modifybooking: 'Modify Reservation',
@@ -1255,6 +1312,7 @@ const msgglobal = {
cancelederrorbooking: 'Cancellation unsuccessfully, try again later',
event: 'Event',
starttime: 'From',
enddate: 'to',
endtime: 'to',
duration: 'Duration',
hours: 'Hours',
@@ -1277,6 +1335,11 @@ const msgglobal = {
teachertitle: 'Teacher',
peoplebooked: 'Booked',
},
msgs: {
message: 'Messaggio',
messages: 'Messaggi',
nomessage: 'Nessun Messaggio'
},
event: {
_id: 'id',
typol: 'Typology',

View File

@@ -13,7 +13,7 @@ import { costanti } from '@src/store/Modules/costanti'
import { tools } from '@src/store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import * as ApiTables from '@src/store/Modules/ApiTables'
import { CalendarStore, GlobalStore, Projects, Todos, UserStore } from '@store'
import { CalendarStore, GlobalStore, MessageStore, Projects, Todos, UserStore } from '@store'
import messages from '../../statics/i18n'
import globalroutines from './../../globalroutines/index'
@@ -270,7 +270,7 @@ namespace Mutations {
}
function getListByTable(table): any[] {
if (table === 'myevents')
if (table === tools.TABEVENTS)
return CalendarStore.state.eventlist
else if (table === 'operators')
return CalendarStore.state.operators
@@ -282,6 +282,8 @@ namespace Mutations {
return CalendarStore.state.bookedevent
else if (table === 'users')
return UserStore.state.usersList
else if (table === 'sendmsgs')
return MessageStore.state.last_msgs
else
return null
@@ -417,8 +419,8 @@ namespace Actions {
options,
subs: newSub,
others: {
userId: UserStore.state.userId,
access: UserStore.state.tokens[0].access
userId: UserStore.state.my._id,
access: UserStore.state.my.tokens[0].access
}
}
@@ -513,7 +515,7 @@ namespace Actions {
async function checkUpdates(context) {
console.log('checkUpdates')
// if (UserStore.state.userId === '')
// if (UserStore.state.my._id === '')
// return false // Login not made
state.networkDataReceived = false
@@ -533,6 +535,12 @@ namespace Actions {
UserStore.mutations.setusersList(res.data.usersList)
}
if (res.data.last_msgs) {
MessageStore.state.last_msgs = [...res.data.last_msgs]
}
// console.log('MessageStore.state.last_msgs', MessageStore.state.last_msgs)
// console.log('********** res', 'state.todos', state.todos, 'checkPending', checkPending)
// After Login will store into the indexedDb...
@@ -593,7 +601,7 @@ namespace Actions {
}
async function DeleteRec(context, { table, id }) {
console.log('DeleteRec', id)
console.log('DeleteRec', table, id)
return await Api.SendReq('/delrec/' + table + '/' + id, 'DELETE', null)
.then((res) => {
@@ -635,7 +643,7 @@ namespace Actions {
const showall = UserStore.state.isAdmin || UserStore.state.isManager ? '1' : '0'
const myuserid = (UserStore.state.userId) ? UserStore.state.userId : '0'
const myuserid = (UserStore.state.my._id) ? UserStore.state.my._id : '0'
const ris = await Api.SendReq('/loadsite/' + myuserid + '/' + process.env.APP_ID + '/' + showall, 'GET', null)
.then((res) => {

View File

@@ -46,7 +46,7 @@ function getarrByCategory(category: string) {
function initcat() {
const rec = Getters.getters.getRecordEmpty()
rec.userId = UserStore.state.userId
rec.userId = UserStore.state.my._id
return rec
}
@@ -62,11 +62,11 @@ function getproj(projects, idproj, tipoproj: string) {
let ris = null
if (tipoproj === RouteNames.myprojects)
ris = projects.filter((proj) => (proj.id_parent === idproj) && (proj.userId === UserStore.state.userId) && (proj.privacyread === Privacy.onlyme))
ris = projects.filter((proj) => (proj.id_parent === idproj) && (proj.userId === UserStore.state.my._id) && (proj.privacyread === Privacy.onlyme))
else if (tipoproj === RouteNames.projectsshared)
ris = projects.filter((proj) => (proj.id_parent === idproj) && (proj.userId === UserStore.state.userId) && (proj.privacyread !== Privacy.onlyme))
ris = projects.filter((proj) => (proj.id_parent === idproj) && (proj.userId === UserStore.state.my._id) && (proj.privacyread !== Privacy.onlyme))
else if (tipoproj === RouteNames.projectsall)
ris = projects.filter((proj) => (proj.id_parent === idproj) && (proj.userId !== UserStore.state.userId) )
ris = projects.filter((proj) => (proj.id_parent === idproj) && (proj.userId !== UserStore.state.my._id) )
// console.log('idproj', idproj, 'projects', projects, 'getproj', tipoproj, 'ris=', ris)
@@ -168,7 +168,7 @@ namespace Getters {
if (!!UserStore.state) {
if (UserStore.state.userId === proj.userId) // If it's the owner
if (UserStore.state.my._id === proj.userId) // If it's the owner
return true
return (proj.privacyread === Privacy.all) ||
@@ -186,7 +186,7 @@ namespace Getters {
if (!!UserStore) {
if (!!UserStore.state)
return ((UserStore.state.userId === proj.userId) || (proj.privacywrite === Privacy.all)) // If it's the owner
return ((UserStore.state.my._id === proj.userId) || (proj.privacywrite === Privacy.all)) // If it's the owner
else
return false
}
@@ -289,13 +289,13 @@ namespace Actions {
}
}
// if (UserStore.state.userId === '') {
// if (UserStore.state.my._id === '') {
// return false // Login not made
// }
console.log('dbLoad', nametable, checkPending, 'userid=', UserStore.state.userId)
console.log('dbLoad', nametable, checkPending, 'userid=', UserStore.state.my._id)
const ris = await Api.SendReq('/projects/' + UserStore.state.userId, 'GET', null)
const ris = await Api.SendReq('/projects/' + UserStore.state.my._id, 'GET', null)
.then((res) => {
if (res.data.projects) { // console.log('RISULTANTE CATEGORIES DAL SERVER = ', res.data.categories)
stateglob.projects = res.data.projects

View File

@@ -1,5 +1,5 @@
import Api from '@api'
import { IBookedEvent, ICalendarState, IEvents } from 'model'
import { IBookedEvent, ICalendarState, IEvents, IMessage } from 'model'
import { ILinkReg, IResult, IIdToken, IToken } from 'model/other'
import { storeBuilder } from '../Store'
@@ -9,7 +9,7 @@ import { tools } from '../../tools'
import translate from '../../../../globalroutines/util'
import * as Types from '../../../Api/ApiTypes'
import { db_data } from '@src/db/db_data'
import { UserStore } from '@store'
import { GlobalStore, UserStore } from '@store'
import { lists } from '@src/store/Modules/lists'
// State
@@ -50,11 +50,11 @@ const stateGetter = b.state()
namespace Getters {
const findEventBooked = b.read((mystate: ICalendarState) => (myevent: IEvents, isconfirmed: boolean) => {
return mystate.bookedevent.find((bookedevent) => (bookedevent.id_bookedevent === myevent._id) && (bookedevent.userId === UserStore.state.userId) && ((isconfirmed && bookedevent.booked) || (!isconfirmed)))
return mystate.bookedevent.find((bookedevent) => (bookedevent.id_bookedevent === myevent._id) && (bookedevent.userId === UserStore.state.my._id) && ((isconfirmed && bookedevent.booked) || (!isconfirmed)))
}, 'findEventBooked')
const getNumParticipants = b.read((mystate: ICalendarState) => (myevent: IEvents, showall) => {
const myarr = mystate.bookedevent.filter((bookedevent) => (bookedevent.id_bookedevent === myevent._id) && (bookedevent.booked) && (showall || (!showall && bookedevent.userId === UserStore.state.userId) ))
const myarr = mystate.bookedevent.filter((bookedevent) => (bookedevent.id_bookedevent === myevent._id) && (bookedevent.booked) && (showall || (!showall && bookedevent.userId === UserStore.state.my._id) ))
if (myarr)
return myarr.reduce((sum, bookedevent) => sum + bookedevent.numpeople, 0)
else
@@ -62,7 +62,7 @@ namespace Getters {
}, 'getNumParticipants')
const getEventsBookedByIdEvent = b.read((mystate: ICalendarState) => (idevent, showall) => {
return mystate.bookedevent.filter((bookedevent) => (bookedevent.id_bookedevent === idevent) && (bookedevent.booked) && (showall || (!showall && bookedevent.userId === UserStore.state.userId) ))
return mystate.bookedevent.filter((bookedevent) => (bookedevent.id_bookedevent === idevent) && (bookedevent.booked) && (showall || (!showall && bookedevent.userId === UserStore.state.my._id) ))
}, 'getEventsBookedByIdEvent')
const getTeacherName = b.read((mystate: ICalendarState) => (teacherusername) => {
@@ -134,7 +134,7 @@ namespace Getters {
namespace Mutations {
// function authUser(state: ICalendarState, data: ICalendarState) {
// state.userId = data.userId
// state._id = data._id
// }
//
// export const mutations = {
@@ -153,7 +153,7 @@ namespace Actions {
numpeople: bookevent.numpeople,
msgbooking: bookevent.msgbooking,
datebooked: bookevent.datebooked,
userId: UserStore.state.userId,
userId: UserStore.state.my._id,
booked: bookevent.booked,
modified: bookevent.modified
}
@@ -190,6 +190,10 @@ namespace Actions {
}
async function CancelEvent(context, { id }) {
return await GlobalStore.actions.DeleteRec({table: tools.TABEVENTS, id } )
}
async function CancelBookingEvent(context, { ideventbook, notify }) {
console.log('CALSTORE: CancelBookingEvent', ideventbook, notify)
@@ -216,7 +220,8 @@ namespace Actions {
export const actions = {
BookEvent: b.dispatch(BookEvent),
CancelBookingEvent: b.dispatch(CancelBookingEvent)
CancelBookingEvent: b.dispatch(CancelBookingEvent),
CancelEvent: b.dispatch(CancelEvent)
}
// async function resetpwd(context, paramquery: ICalendarState) {

View File

@@ -52,7 +52,7 @@ function gettodosByCategory(category: string): any[] {
function initcat() {
const rec = Getters.getters.getRecordEmpty()
rec.userId = UserStore.state.userId
rec.userId = UserStore.state.my._id
return rec
@@ -67,7 +67,7 @@ namespace Getters {
const objtodo: ITodo = {
// _id: tools.getDateNow().toISOString(), // Create NEW
_id: objectId(),
userId: UserStore.state.userId,
userId: UserStore.state.my._id,
descr: '',
priority: tools.Priority.PRIORITY_NORMAL,
statustodo: tools.Status.OPENED,
@@ -258,15 +258,15 @@ namespace Actions {
if (!static_data.functionality.ENABLE_PROJECTS_LOADING)
return null
console.log('dbLoad', nametable, checkPending, 'userid=', UserStore.state.userId)
console.log('dbLoad', nametable, checkPending, 'userid=', UserStore.state.my._id)
// if (UserStore.state.userId === '') {
// if (UserStore.state.my._id === '') {
// return new Types.AxiosError(0, null, 0, '')
// }
let ris = null
ris = await Api.SendReq('/todos/' + UserStore.state.userId, 'GET', null)
ris = await Api.SendReq('/todos/' + UserStore.state.my._id, 'GET', null)
.then((res) => {
if (res.data.todos) { // console.log('RISULTANTE CATEGORIES DAL SERVER = ', res.data.categories)
state.todos = res.data.todos

View File

@@ -1,5 +1,5 @@
import Api from '@api'
import { ISignupOptions, ISigninOptions, IUserState, IUserList } from 'model'
import { ISignupOptions, ISigninOptions, IUserState, IUserFields } from 'model'
import { ILinkReg, IResult, IIdToken, IToken } from 'model/other'
import { storeBuilder } from './Store/Store'
import router from '@router'
@@ -15,23 +15,25 @@ import { db_data } from '@src/db/db_data'
import translate from './../../globalroutines/util'
import * as Types from '@src/store/Api/ApiTypes'
import { ICfgServer } from '@src/model'
import { ICalendarState, ICfgServer } from '@src/model'
import { shared_consts } from '../../common/shared_vuejs'
const bcrypt = require('bcryptjs')
// State
const state: IUserState = {
userId: '',
my: {
_id: '',
email: '',
username: '',
name: '',
surname: '',
password: '',
tokens: [],
verified_email: false
},
lang: process.env.LANG_DEFAULT,
repeatPassword: '',
tokens: [],
verified_email: false,
categorySel: 'personal',
servercode: 0,
x_auth_token: '',
@@ -51,15 +53,15 @@ namespace Getters {
const isUserInvalid = b.read((mystate) => {
try {
const ris = (mystate.userId === undefined) || (mystate.userId.trim() === '') || (mystate.tokens[0] === undefined)
// console.log('state.userId', state.userId, 'ris', ris)
const ris = (mystate.my._id === undefined) || (mystate.my._id.trim() === '') || (mystate.my.tokens[0] === undefined)
// console.log('state._id', state._id, 'ris', ris)
return ris
} catch (e) {
return true
}
}, 'isUserInvalid')
const lang = b.read((state) => {
const lang = b.read((mystate) => {
if (state.lang !== '') {
return state.lang
} else {
@@ -68,9 +70,9 @@ namespace Getters {
}, 'lang')
// const tok = b.read(state => {
// if (state.tokens) {
// if (typeof state.tokens[0] !== 'undefined') {
// return state.tokens[0].token
// if (state.my.tokens) {
// if (typeof state.my.tokens[0] !== 'undefined') {
// return state.my.tokens[0].token
// } else {
// return ''
// }
@@ -79,15 +81,15 @@ namespace Getters {
// }
// }, 'tok')
const isServerError = b.read((state) => {
const isServerError = b.read((mystate) => {
return (state.servercode === tools.ERR_SERVERFETCH)
}, 'isServerError')
const getServerCode = b.read((state) => {
const getServerCode = b.read((mystate) => {
return state.servercode
}, 'getServerCode')
const getNameSurnameByUserId = b.read((state: IUserState) => (userId: string) => {
const getNameSurnameByUserId = b.read((mystate: IUserState) => (userId: string) => {
const user = UserStore.getters.getUserByUserId(userId)
if (user)
return user.name + ' ' + user.surname
@@ -95,30 +97,56 @@ namespace Getters {
return '(' + userId + ')'
}, 'getNameSurnameByUserId')
const getNameSurnameByUsername = b.read((mystate: IUserState) => (username: string) => {
const user = UserStore.getters.getUserByUsername(username)
if (user)
return user.name + ' ' + user.surname
else
return '(' + username + ')'
}, 'getNameSurnameByUsername')
const getUsersList = b.read((mystate: IUserState) => {
return mystate.usersList
}, 'getUsersList')
const IsMyFriend = b.read((state) => (userIdOwner) => {
const IsMyFriend = b.read((mystate) => (userIdOwner) => {
// ++TODO Check if userIdOwner is my friend
// userIdOwner is my friend ?
return true
}, 'IsMyFriend')
const IsMyGroup = b.read((state) => (userIdOwner) => {
const IsMyGroup = b.read((mystate) => (userIdOwner) => {
// ++TODO Check if userIdOwner is on my groups
// userIdOwner is on my groups ?
return true
}, 'IsMyGroup')
const getUserByUserId = b.read((mystate: IUserState) => (userId): IUserState => {
const getUserByUserId = b.read((mystate: IUserState) => (userId): IUserFields => {
// Check if is this User!
if (state.userId === userId)
return state
if (state.my._id === userId)
return state.my
return mystate.usersList.find((item) => item._id === userId)
}, 'getUserByUserId')
const getUserByUsername = b.read((mystate: IUserState) => (username): IUserFields => {
// Check if is this User!
if (state.my.username === username)
return state.my
return mystate.usersList.find((item) => item.username === username)
}, 'getUserByUsername')
const getImgByUsername = b.read((mystate: IUserState) => (username): string => {
// Check if is this User!
const myrec = UserStore.getters.getUserByUsername(username)
if (myrec && !!myrec.img) {
return myrec.img
} else {
return 'images/avatar/avatar3_small.png'
}
}, 'getImgByUsername')
export const getters = {
get isUserInvalid() {
return isUserInvalid()
@@ -147,85 +175,92 @@ namespace Getters {
get getUserByUserId() {
return getUserByUserId()
},
get getNameSurnameByUsername() {
return getNameSurnameByUsername()
},
get getImgByUsername() {
return getImgByUsername()
},
get getUserByUsername() {
return getUserByUsername()
},
get getUsersList() {
return getUsersList()
}
// get fullName() { return fullName();},
}
}
namespace Mutations {
function authUser(mystate: IUserState, data: IUserState) {
mystate.userId = data.userId
mystate.username = data.username
mystate.name = data.name
mystate.surname = data.surname
mystate.perm = data.perm
mystate.isAdmin = tools.isBitActive(mystate.perm, shared_consts.Permissions.Admin)
mystate.isManager = tools.isBitActive(mystate.perm, shared_consts.Permissions.Manager)
function authUser(mystate: IUserState, data: IUserFields) {
mystate.my = {...data}
mystate.isAdmin = tools.isBitActive(mystate.my.perm, shared_consts.Permissions.Admin)
mystate.isManager = tools.isBitActive(mystate.my.perm, shared_consts.Permissions.Manager)
// console.log('authUser', 'state.isAdmin', mystate.isAdmin)
console.table(mystate)
console.table(data)
if (data.verified_email) {
mystate.verified_email = data.verified_email
// if (data.my.verified_email) {
// mystate.my.verified_email = data.my.verified_email
// }
//
// if (data.categorySel) {
// mystate.categorySel = data.categorySel
// } // ??
mystate.my.tokens = []
resetArrToken(mystate.my.tokens)
mystate.my.tokens.push({ access: 'auth', token: mystate.x_auth_token, data_login: tools.getDateNow() })
// console.log('state.my.tokens', state.my.tokens)
}
if (data.categorySel) {
mystate.categorySel = data.categorySel
} // ??
resetArrToken(mystate.tokens)
mystate.tokens.push({ access: 'auth', token: mystate.x_auth_token, data_login: tools.getDateNow() })
// console.log('state.tokens', state.tokens)
function setpassword(mystate: IUserState, newstr: string) {
mystate.my.password = newstr
}
function setpassword(state: IUserState, newstr: string) {
state.password = newstr
}
function setusersList(mystate: IUserState, usersList: IUserList[]) {
function setusersList(mystate: IUserState, usersList: IUserFields[]) {
// console.log('setusersList', usersList)
mystate.usersList = [...usersList]
}
function setemail(state: IUserState, newstr: string) {
state.email = newstr
function setemail(mystate: IUserState, newstr: string) {
mystate.my.email = newstr
}
function setlang(state: IUserState, newstr: string) {
function setlang(mystate: IUserState, newstr: string) {
console.log('SETLANG', newstr)
state.lang = newstr
mystate.lang = newstr
tools.setLangAtt(newstr)
localStorage.setItem(tools.localStorage.lang, state.lang)
}
function UpdatePwd(state: IUserState, x_auth_token: string) {
state.x_auth_token = x_auth_token
if (!state.tokens) {
state.tokens = []
function UpdatePwd(mystate: IUserState, x_auth_token: string) {
mystate.x_auth_token = x_auth_token
if (!mystate.my.tokens) {
mystate.my.tokens = []
}
state.tokens.push({ access: 'auth', token: x_auth_token, data_login: tools.getDateNow() })
mystate.my.tokens.push({ access: 'auth', token: x_auth_token, data_login: tools.getDateNow() })
}
function setServerCode(state: IUserState, num: number) {
state.servercode = num
function setServerCode(mystate: IUserState, num: number) {
mystate.servercode = num
}
function setResStatus(state: IUserState, status: number) {
state.resStatus = status
function setResStatus(mystate: IUserState, status: number) {
mystate.resStatus = status
}
function setAuth(state: IUserState, x_auth_token: string) {
function setAuth(mystate: IUserState, x_auth_token: string) {
state.x_auth_token = x_auth_token
mystate.x_auth_token = x_auth_token
}
function resetArrToken(arrtokens) {
if (!arrtokens.tokens) {
arrtokens.tokens = []
if (!arrtokens) {
arrtokens = []
}
// Take only the others access (from others Browser)
@@ -234,25 +269,25 @@ namespace Mutations {
})
}
function clearAuthData(state: IUserState) {
state.userId = ''
state.username = ''
state.name = ''
state.surname = ''
resetArrToken(state.tokens)
state.verified_email = false
state.categorySel = 'personal'
function clearAuthData(mystate: IUserState) {
mystate.my._id = ''
mystate.my.username = ''
mystate.my.name = ''
mystate.my.surname = ''
resetArrToken(mystate.my.tokens)
mystate.my.verified_email = false
mystate.categorySel = 'personal'
state.servercode = 0
state.resStatus = 0
state.isLogged = false
state.x_auth_token = ''
mystate.servercode = 0
mystate.resStatus = 0
mystate.isLogged = false
mystate.x_auth_token = ''
}
function setErrorCatch(state: IUserState, axerr: Types.AxiosError) {
function setErrorCatch(mystate: IUserState, axerr: Types.AxiosError) {
try {
if (state.servercode !== tools.ERR_SERVERFETCH) {
state.servercode = axerr.getCode()
if (mystate.servercode !== tools.ERR_SERVERFETCH) {
mystate.servercode = axerr.getCode()
}
console.log('Err catch: (servercode:', axerr.getCode(), axerr.getMsgError(), ')')
} catch (e) {
@@ -260,11 +295,11 @@ namespace Mutations {
}
}
function getMsgError(state: IUserState, err: number) {
function getMsgError(mystate: IUserState, err: number) {
let msgerrore = ''
if (err !== tools.OK) {
msgerrore = 'Error [' + state.servercode + ']: '
if (state.servercode === tools.ERR_SERVERFETCH) {
msgerrore = 'Error [' + mystate.servercode + ']: '
if (mystate.servercode === tools.ERR_SERVERFETCH) {
msgerrore = translate('fetch.errore_server')
} else {
msgerrore = translate('fetch.errore_generico')
@@ -291,7 +326,7 @@ namespace Mutations {
clearAuthData: b.commit(clearAuthData),
setErrorCatch: b.commit(setErrorCatch),
getMsgError: b.commit(getMsgError),
setusersList: b.commit(setusersList),
setusersList: b.commit(setusersList)
}
}
@@ -311,8 +346,8 @@ namespace Actions {
async function resetpwd(context, paramquery: IUserState) {
const usertosend = {
email: paramquery.email,
password: paramquery.password,
email: paramquery.my.email,
password: paramquery.my.password,
tokenforgot: paramquery.tokenforgot
}
console.log(usertosend)
@@ -330,11 +365,10 @@ namespace Actions {
}
async function requestpwd(context, paramquery: IUserState) {
const usertosend = {
email: paramquery.email
email: paramquery.my.email
}
console.log(usertosend)
@@ -408,31 +442,21 @@ namespace Actions {
Mutations.mutations.setServerCode(res.status)
if (res.status === 200) {
const userId = newuser._id
const username = authData.username
const name = authData.name
const surname = authData.surname
if (process.env.DEV) {
console.log('USERNAME = ' + username)
console.log('IDUSER= ' + userId)
console.log('USERNAME = ' + newuser.username)
console.log('IDUSER= ' + newuser._id)
}
Mutations.mutations.authUser({
userId,
username,
name,
surname,
verified_email: false
})
Mutations.mutations.authUser(newuser)
const now = tools.getDateNow()
// const expirationDate = new Date(now.getTime() + myres.data.expiresIn * 1000);
const expirationDate = new Date(now.getTime() * 1000)
localStorage.setItem(tools.localStorage.lang, state.lang)
localStorage.setItem(tools.localStorage.userId, userId)
localStorage.setItem(tools.localStorage.username, username)
localStorage.setItem(tools.localStorage.name, name)
localStorage.setItem(tools.localStorage.surname, surname)
localStorage.setItem(tools.localStorage.userId, newuser._id)
localStorage.setItem(tools.localStorage.username, newuser.username)
localStorage.setItem(tools.localStorage.name, newuser.name)
localStorage.setItem(tools.localStorage.surname, newuser.surname)
localStorage.setItem(tools.localStorage.token, state.x_auth_token)
localStorage.setItem(tools.localStorage.expirationDate, expirationDate.toString())
localStorage.setItem(tools.localStorage.verified_email, String(false))
@@ -518,38 +542,26 @@ namespace Actions {
if (res.success) {
GlobalStore.mutations.SetwasAlreadySubOnDb(res.data.subsExistonDb)
const myuser: IUserState = res.data.usertosend
const myuser: IUserFields = res.data.usertosend
if (myuser) {
const userId = myuser.userId
const username = authData.username
const name = myuser.name
const surname = myuser.surname
const verified_email = myuser.verified_email
console.table(myuser)
Mutations.mutations.authUser({
userId,
username,
name,
surname,
verified_email,
perm: myuser.perm
})
Mutations.mutations.authUser(myuser)
const now = tools.getDateNow()
// const expirationDate = new Date(now.getTime() + myres.data.expiresIn * 1000);
const expirationDate = new Date(now.getTime() * 1000)
localStorage.setItem(tools.localStorage.lang, state.lang)
localStorage.setItem(tools.localStorage.userId, userId)
localStorage.setItem(tools.localStorage.username, username)
localStorage.setItem(tools.localStorage.name, name)
localStorage.setItem(tools.localStorage.surname, surname)
localStorage.setItem(tools.localStorage.userId, myuser._id)
localStorage.setItem(tools.localStorage.username, myuser.username)
localStorage.setItem(tools.localStorage.name, myuser.name)
localStorage.setItem(tools.localStorage.surname, myuser.surname)
localStorage.setItem(tools.localStorage.perm, String(myuser.perm) || '')
localStorage.setItem(tools.localStorage.img, String(myuser.img) || '')
localStorage.setItem(tools.localStorage.token, state.x_auth_token)
localStorage.setItem(tools.localStorage.expirationDate, expirationDate.toString())
localStorage.setItem(tools.localStorage.isLogged, String(true))
localStorage.setItem(tools.localStorage.verified_email, String(verified_email))
localStorage.setItem(tools.localStorage.verified_email, String(myuser.verified_email))
localStorage.setItem(tools.localStorage.wasAlreadySubOnDb, String(GlobalStore.state.wasAlreadySubOnDb))
}
@@ -582,6 +594,7 @@ namespace Actions {
localStorage.removeItem(tools.localStorage.username)
localStorage.removeItem(tools.localStorage.name)
localStorage.removeItem(tools.localStorage.surname)
localStorage.removeItem(tools.localStorage.img)
localStorage.removeItem(tools.localStorage.perm)
localStorage.removeItem(tools.localStorage.isLogged)
// localStorage.removeItem(rescodes.localStorage.leftDrawerOpen)
@@ -647,26 +660,28 @@ namespace Actions {
const expirationDate = new Date(String(expirationDateStr))
const now = tools.getDateNow()
if (now < expirationDate) {
const userId = String(localStorage.getItem(tools.localStorage.userId))
const _id = String(localStorage.getItem(tools.localStorage.userId))
const username = String(localStorage.getItem(tools.localStorage.username))
const name = String(localStorage.getItem(tools.localStorage.name))
const surname = String(localStorage.getItem(tools.localStorage.surname))
const verified_email = localStorage.getItem(tools.localStorage.verified_email) === 'true'
const perm = parseInt(localStorage.getItem(tools.localStorage.perm), 10)
const img = String(localStorage.getItem(tools.localStorage.img))
GlobalStore.state.wasAlreadySubOnDb = localStorage.getItem(tools.localStorage.wasAlreadySubOnDb) === 'true'
console.log('************* autologin userId', userId)
console.log('************* autologin _id', _id)
UserStore.mutations.setAuth(token)
Mutations.mutations.authUser({
userId,
_id,
username,
name,
surname,
verified_email,
perm
perm,
img
})
isLogged = true
@@ -675,7 +690,7 @@ namespace Actions {
await setGlobal(isLogged)
// console.log('autologin userId STATE ', state.userId)
// console.log('autologin _id STATE ', state._id)
return true
} catch (e) {
@@ -700,7 +715,6 @@ namespace Actions {
}
*/
export const actions = {
autologin_FromLocalStorage: b.dispatch(autologin_FromLocalStorage),
logout: b.dispatch(logout),

View File

@@ -1,6 +1,7 @@
export {storeBuilder} from './Store/Store'
export {default as GlobalStore} from './GlobalStore'
export {default as UserStore} from './UserStore'
export {default as MessageStore} from './MessageStore'
export {default as Todos} from './Todos'
export {default as Projects} from './Projects'
export {default as CalendarStore} from './Store/calendar/CalendarStore'

View File

@@ -17,6 +17,7 @@ export const lists = {
DELETE_RECTABLE: 300,
DUPLICATE_RECTABLE: 310,
DELETE_EVENT: 320,
CAN_EDIT_TABLE: 400,
SHOW_PREV_REC: 401

View File

@@ -1,5 +1,6 @@
export const serv_constants = {
RIS_CODE_TODO_CREATING_NOTMYUSER: -1001,
RIS_CODE_NOT_MY_USERNAME: -1010,
RIS_CODE_ERR: -99,
RIS_CODE_EMAIL_ALREADY_VERIFIED: -5,

View File

@@ -26,6 +26,9 @@ import { func_tools } from '@src/store/Modules/toolsext'
import { serv_constants } from '@src/store/Modules/serv_constants'
import { shared_consts } from '@src/common/shared_vuejs'
import { dom } from 'quasar'
const { height, width } = dom
export interface INotify {
color?: string | 'primary'
textColor?: string
@@ -33,6 +36,8 @@ export interface INotify {
}
export const tools = {
TABEVENTS: 'myevents',
MAX_CHARACTERS: 60,
projects: 'projects',
todos: 'todos',
@@ -74,7 +79,8 @@ export const tools = {
name: 'nm',
surname: 'sn',
perm: 'pm',
lang: 'lg'
lang: 'lg',
img: 'img'
},
Priority: {
@@ -1331,6 +1337,16 @@ export const tools = {
} else
tools.showNegativeNotif(myself.$q, myself.$t('cal.cancelederrorbooking'))
})
} else if (func === lists.MenuAction.DELETE_EVENT) {
console.log('param1', par.param1, 'id', par.param1._id)
CalendarStore.actions.CancelEvent({ id: par.param1._id }).then((ris) => {
if (ris) {
// Remove this record from my list
CalendarStore.state.eventlist = CalendarStore.state.eventlist.filter((event) => (event._id !== par.param1._id))
tools.showPositiveNotif(myself.$q, myself.$t('cal.canceledevent') + ' "' + par.param1.title + '"')
} else
tools.showNegativeNotif(myself.$q, myself.$t('cal.cancelederrorevent'))
})
} else if (func === lists.MenuAction.DELETE_RECTABLE) {
console.log('param1', par.param1)
GlobalStore.actions.DeleteRec({ table, id: par.param1 }).then((ris) => {
@@ -1656,6 +1672,36 @@ export const tools = {
return ''
},
getstrDateTimeEvent(mythis, myevent, withhtml) {
let mystr = ''
// is same day?
if (tools.getstrDate(myevent.dateTimeStart) === tools.getstrDate(myevent.dateTimeEnd)) {
if (withhtml) {
mystr += `<span class="cal__where-content">${tools.getstrDate(myevent.dateTimeStart)}</span>
<span class="cal__hours-content">${mythis.$t('cal.starttime')} ${ tools.getstrTime(myevent.dateTimeStart) }
${ mythis.$t('cal.endtime')} ${ tools.getstrTime(myevent.dateTimeEnd) }`
} else {
mystr = `${tools.getstrDate(myevent.dateTimeStart)}
${mythis.$t('cal.starttime')} ${ tools.getstrTime(myevent.dateTimeStart) }
${ mythis.$t('cal.endtime')}: ${ tools.getstrTime(myevent.dateTimeEnd) }`
}
} else {
mystr = `<span class="cal__where-content">${tools.getstrDate(myevent.dateTimeStart)}</span>
<span class="cal__hours-content">${mythis.$t('cal.starttime')} ${ tools.getstrTime(myevent.dateTimeStart) } </span>
${ mythis.$t('cal.enddate')} ${tools.getstrDate(myevent.dateTimeEnd)}
<span class="cal__hours-content">${ mythis.$t('cal.endtime')}: ${ tools.getstrTime(myevent.dateTimeEnd) } </span>`
}
if (myevent.infoextra) {
mystr += `<span class="cal__hours">
<span class="cal__hours-title">${mythis.$t('cal.hours')}: </span>
<span class="cal__hours-content">${ myevent.infoextra } </span>
</span>
</span>`
}
return mystr
},
getstrDateTime(mytimestamp) {
// console.log('getstrDate', mytimestamp)
if (!!mytimestamp)
@@ -1664,13 +1710,22 @@ export const tools = {
return ''
},
getstrDateEmailTime(mythis, mytimestamp) {
getstrDateTimeShort(mytimestamp) {
// console.log('getstrDate', mytimestamp)
if (!!mytimestamp)
return date.formatDate(mytimestamp, 'DD/MM/YYYY') + ' ' + mythis.$t('starttime') + ' ' + date.formatDate(mytimestamp, 'HH:mm')
return date.formatDate(mytimestamp, 'DD/MM HH:mm')
else
return ''
},
getstrDateEmailTime(mythis, mytimestamp) {
// console.log('getstrDate', mytimestamp)
if (!!mytimestamp)
return date.formatDate(mytimestamp, 'DD/MM/YYYY') + ' ' + mythis.$t('cal.starttime') + ' ' + date.formatDate(mytimestamp, 'HH:mm')
else
return ''
}
,
getstrMMMDate(mytimestamp) {
// console.log('getstrDate', mytimestamp)
if (!!mytimestamp)
@@ -1681,11 +1736,16 @@ export const tools = {
,
getstrYYMMDDDate(mytimestamp) {
return date.formatDate(mytimestamp, 'YYYY-MM-DD')
},
}
,
getstrYYMMDDDateTime(mytimestamp) {
return date.formatDate(mytimestamp, 'YYYY-MM-DD HH:mm')
},
getstrYYMMDDDateTimeAll(mytimestamp) {
return date.formatDate(mytimestamp, 'YYYY-MM-DD HH:mm:ss')
},
// mystrdate "26.04.2013"
convertstrtoDate(mystrdate
:
@@ -1714,7 +1774,8 @@ export const tools = {
}
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
},
}
,
firstchars(value, numchars = 200) {
if (!value) {
@@ -1728,7 +1789,8 @@ export const tools = {
} catch (e) {
return value
}
},
}
,
getDateNow() {
const mydate = new Date()
@@ -1747,16 +1809,22 @@ export const tools = {
return new Date().valueOf()
},
isMainProject(idproj) {
return idproj === process.env.PROJECT_ID_MAIN
gettimestampByDate(mydate) {
return mydate.toString()
},
getUrlByTipoProj(tipoproj, name?: string) {
isMainProject(idproj) {
return idproj === process.env.PROJECT_ID_MAIN
}
,
getUrlByTipoProj(tipoproj, name ?: string) {
if (!!name)
return '/' + name + '/'
else
return '/' + tipoproj + '/'
},
}
,
// convertMenuListInListRoutes(arrlista: IMenuList[]) {
// const lista = []
@@ -1784,15 +1852,18 @@ export const tools = {
return Privacy.onlyme
else
return Privacy.all
},
}
,
getprivacywritebytipoproj(tipoproj) {
return Privacy.onlyme
},
}
,
addRoute(myarr, values) {
myarr.push(values)
},
}
,
displayConfirmNotification() {
let options = null
if ('serviceWorker' in navigator) {
@@ -1819,7 +1890,8 @@ export const tools = {
})
}
}
},
}
,
dataURItoBlob(dataURI) {
const byteString = atob(dataURI.split(',')[1])
@@ -1831,7 +1903,8 @@ export const tools = {
}
const blob = new Blob([ab], { type: mimeString })
return blob
},
}
,
showNotificationExample() {
let options = null
@@ -1858,11 +1931,13 @@ export const tools = {
swreg.showNotification('aaa', options)
})
}
},
}
,
getemailto(text) {
return 'mailto:' + text
},
}
,
askfornotification() {
tools.showNotif(this.$q, this.$t('notification.waitingconfirm'), { color: 'positive', icon: 'notifications' })
@@ -1878,11 +1953,13 @@ export const tools = {
}
})
},
}
,
heightgallery() {
return tools.heightGallVal().toString() + 'px'
},
}
,
heightGallVal() {
let maxh2 = 0
@@ -1904,9 +1981,10 @@ export const tools = {
}
return maxh2
},
}
,
myheight_imgtitle(myheight?, myheightmobile?) {
myheight_imgtitle(myheight ?, myheightmobile ?) {
let maxheight = 0
if (!!myheight) {
maxheight = myheight
@@ -1940,7 +2018,8 @@ export const tools = {
// console.log('ris', ris)
return ris
},
}
,
myheight_dialog() {
if (Screen.width < 400) {
@@ -1950,9 +2029,10 @@ export const tools = {
} else {
return '500'
}
},
}
,
styles_imgtitle(sized?: string) {
styles_imgtitle(sized ?: string) {
if (!!sized) {
return sized
} else {
@@ -1962,7 +2042,8 @@ export const tools = {
return 'max-height: 350px'
}
}
},
}
,
/*
<q-img
@@ -1988,7 +2069,8 @@ export const tools = {
'(min-width: 400px) and (max-width: 800px) 800w, ' +
'(min-width: 800px) and (max-width: 1200px) 1200w, ' +
'(min-width: 1200px) 1600w'
},
}
,
maxwidth_imgtitle() {
if (Screen.width < 400) {
@@ -1996,11 +2078,13 @@ export const tools = {
} else {
return 'max-width: 350px'
}
},
}
,
isMobile() {
return (Screen.width < 400)
},
}
,
mywidth_imgtitle() {
if (Screen.width < 400) {
@@ -2010,11 +2094,13 @@ export const tools = {
} else {
return '350'
}
},
}
,
mymargin_imgtitle() {
return 'auto'
},
}
,
showthumbnails() {
if (Screen.width < 400) {
@@ -2024,7 +2110,8 @@ export const tools = {
} else {
return true
}
},
}
,
padTime(val) {
val = Math.floor(val)
@@ -2032,9 +2119,10 @@ export const tools = {
return '0' + val
}
return val + ''
},
}
,
getLocale(vero?: boolean) {
getLocale(vero ?: boolean) {
if (UserStore) {
if (UserStore.state) {
return UserStore.state.lang
@@ -2044,15 +2132,18 @@ export const tools = {
return process.env.LANG_DEFAULT
else
return ''
},
}
,
addDays(mydate, days) {
return date.addToDate(mydate, { days })
},
}
,
addMinutes(mydate, minutes) {
return date.addToDate(mydate, { minutes })
},
}
,
gettitlemain(datamain: ITimeLineMain) {
if (datamain.titlemain[toolsext.getLocale()])
@@ -2061,7 +2152,8 @@ export const tools = {
return datamain.titlemain[static_data.arrLangUsed[0]]
}
},
}
,
getwwithwhocoll(datamain: ICollaborations) {
if (datamain.withwhom_title[toolsext.getLocale()])
return datamain.withwhom_title[toolsext.getLocale()]
@@ -2069,22 +2161,26 @@ export const tools = {
return datamain.withwhom_title[static_data.arrLangUsed[0]]
}
},
}
,
gettextcoll(data: IColl) {
if (data.subtitle[toolsext.getLocale()])
return data.subtitle[toolsext.getLocale()]
else {
return data.subtitle[static_data.arrLangUsed[0]]
}
},
}
,
gettitlecoll(data: IColl) {
if (data.title[toolsext.getLocale()])
return data.title[toolsext.getLocale()]
else {
return data.title[static_data.arrLangUsed[0]]
}
},
gettextdescr(data: ITimeLineEntry, numdescr = 'description') {
}
,
gettextdescr(data: ITimeLineEntry, numdescr = 'description'
) {
if (!!data[numdescr]) {
if (data[numdescr][toolsext.getLocale()])
return data[numdescr][toolsext.getLocale()]
@@ -2094,7 +2190,8 @@ export const tools = {
} else {
return ''
}
},
}
,
getlink(data: ITimeLineEntry) {
if (data.link_text[toolsext.getLocale()])
@@ -2103,7 +2200,8 @@ export const tools = {
return data.link_text[static_data.arrLangUsed[0]]
}
},
}
,
getlinkurl(data: ITimeLineEntry) {
if (data.link_url_lang) {
@@ -2153,7 +2251,8 @@ export const tools = {
return { path: '', file: fileimg }
}
},
}
,
convertHTMLtoText(myhtml) {
let msg = myhtml
@@ -2164,7 +2263,8 @@ export const tools = {
msg = msg.replace('<br>', '\n')
return msg
},
}
,
gettextevent(mythis, myevent: IEvents) {
// return '"' + myevent.title + '" (' + func_tools.getDateStr(myevent.date) + ') - ' + myevent.time
return '"' + myevent.title + '" (' + tools.getstrDateEmailTime(mythis, myevent.dateTimeStart) + ')'
@@ -2185,7 +2285,8 @@ export const tools = {
// this.$q.lang.set(mylang)
},
}
,
getappname(mythis) {
if (mythis === undefined)
return ''
@@ -2215,7 +2316,8 @@ export const tools = {
globalroutines(mythis, 'loadapp', '')
tools.SignIncheckErrors(mythis, tools.OK, ispageLogin)
},
}
,
loginInCorso(mythis) {
// console.log('loginInCorso')
@@ -2225,9 +2327,10 @@ export const tools = {
msg += ' ' + process.env.MONGODB_HOST
}
mythis.$q.loading.show({ message: msg })
},
}
,
SignIncheckErrors(mythis, riscode, ispageLogin?: boolean) {
SignIncheckErrors(mythis, riscode, ispageLogin ?: boolean) {
// console.log('SignIncheckErrors: ', riscode)
try {
if (riscode === tools.OK) {
@@ -2274,7 +2377,8 @@ export const tools = {
} finally {
// ...
}
},
}
,
SignUpcheckErrors(mythis, riscode: number) {
console.log('SignUpcheckErrors', riscode)
@@ -2297,16 +2401,19 @@ export const tools = {
tools.showNotif(mythis.$q, 'Errore num ' + riscode)
}
},
}
,
isCssColor(color) {
return !!color && !!color.match(/^(#|(rgb|hsl)a?\()/)
},
}
,
displayClasses(eventparam) {
return {
// [`bg-${eventparam.bgcolor}`]: !tools.isCssColor(eventparam.bgcolor),
'text-white': !tools.isCssColor(eventparam.bgcolor)
}
},
}
,
displayStyles(eventparam) {
const s = { color: '' }
if (tools.isCssColor(eventparam.bgcolor)) {
@@ -2314,21 +2421,32 @@ export const tools = {
s.color = colors.luminosity(eventparam.bgcolor) > 0.5 ? 'black' : 'white'
}
return s
},
}
,
CancelBookingEvent(mythis, eventparam: IEvents, bookeventid: string, notify: boolean) {
console.log('CancelBookingEvent ', eventparam)
tools.askConfirm(mythis.$q, translate('cal.titlebooking'), translate('cal.cancelbooking') + ' ' + tools.gettextevent(mythis, eventparam) + '?', translate('dialog.yes'), translate('dialog.no'), mythis, '', lists.MenuAction.DELETE, 0, {
param1: bookeventid,
param2: notify
})
},
}
,
CancelEvent(mythis, eventparam: IEvents) {
console.log('CancelEvent ', eventparam)
tools.askConfirm(mythis.$q, translate('cal.event'), translate('cal.cancelevent') + ' ' + tools.gettextevent(mythis, eventparam) + '?', translate('dialog.yes'), translate('dialog.no'), mythis, '', lists.MenuAction.DELETE_EVENT, 0, {
param1: eventparam,
param2: true
})
}
,
ActionRecTable(mythis, action, table, id, item, askaction) {
console.log('ActionRecTable', id)
return tools.askConfirm(mythis.$q, 'Action', translate(askaction) + '?', translate('dialog.yes'), translate('dialog.no'), mythis, table, action, 0, {
param1: id,
param2: item
})
},
}
,
async createNewRecord(mythis, table, data) {
@@ -2337,7 +2455,8 @@ export const tools = {
data
}
return await GlobalStore.actions.saveTable(mydata)
return await
GlobalStore.actions.saveTable(mydata)
.then((record) => {
if (record) {
tools.showPositiveNotif(mythis.$q, mythis.$t('db.recupdated'))
@@ -2347,6 +2466,13 @@ export const tools = {
return record
})
},
getheight(mythis) {
// return height()
return mythis.$q.screen.height
},
getLastDateReadReset() {
return new Date(1999, 1, 1, 0, 0, 0)
},
isBitActive(bit, whattofind) {
return ((bit & whattofind) === whattofind)

View File

@@ -47,7 +47,7 @@ export default class CfgServer extends Vue {
public selItem(item) {
console.log('item', item)
this.keysel = item.chiave
this.userIdsel = item.userid
this.userIdsel = item.userId
console.log('this.keysel', this.keysel)
}

View File

@@ -68,18 +68,18 @@ export default class Testp1 extends Vue {
}
TestBtn2() {
GlobalStore.state.testp1.mioarray.push({chiave: 'pippo2', userId: UserStore.state.userId, valore: GlobalStore.state.testp1.contatore.toString() })
GlobalStore.state.testp1.mioarray.push({chiave: 'pippo2', userId: UserStore.state.my._id, valore: GlobalStore.state.testp1.contatore.toString() })
}
TestBtnModify() {
// GlobalStore.state.testp1.mioarray[GlobalStore.state.testp1.mioarray.length - 1] = GlobalStore.state.testp1.mioarray[GlobalStore.state.testp1.mioarray.length - 1] + 1
GlobalStore.mutations.setPaoArray({chiave: 'pippo', userId: UserStore.state.userId, valore: '20' } )
GlobalStore.mutations.setPaoArray({chiave: 'pippo', userId: UserStore.state.my._id, valore: '20' } )
}
TestBtnCambiaTutto() {
// GlobalStore.state.testp1.mioarray[GlobalStore.state.testp1.mioarray.length - 1] = GlobalStore.state.testp1.mioarray[GlobalStore.state.testp1.mioarray.length - 1] + 1
GlobalStore.mutations.NewArray([{chiave: 'nuovorec1', userId: UserStore.state.userId, valore: '1' }, {chiave: 'nuovorec2', userId: UserStore.state.userId, valore: '2' }] )
GlobalStore.mutations.NewArray([{chiave: 'nuovorec1', userId: UserStore.state.my._id, valore: '1' }, {chiave: 'nuovorec2', userId: UserStore.state.my._id, valore: '2' }] )
}

View File

@@ -62,12 +62,12 @@
import Vue from 'vue'
import { email, required } from "vuelidate/lib/validators"
import { UserStore } from "../../store/Modules";
import { IUserState } from "../../model";
import { IUserFields, IUserState } from "../../model"
import { tools } from "../../store/Modules/tools";
import { toolsext } from '@src/store/Modules/toolsext'
export default class RequestResetPwd extends Vue{
emailsent = false
form: IUserState = {
form: IUserFields = {
email: '',
tokenforgot: ''
}

View File

@@ -6,7 +6,6 @@ import { UserStore } from '../../../store/Modules'
import globalroutines from '../../../globalroutines/index'
import { tools } from '../../../store/Modules/tools'
// import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'
@Component({

View File

@@ -74,13 +74,13 @@
import Vue from 'vue'
import { required } from "vuelidate/lib/validators"
import { UserStore } from "../../store/Modules";
import { IUserState } from "../../model";
import { IUserFields, IUserState } from "../../model"
import { tools } from "../../store/Modules/tools";
import { toolsext } from '@src/store/Modules/toolsext'
export default class UpdatePassword extends Vue {
emailsent = false
form: IUserState = {
form = {
password: '',
repeatPassword: '',
tokenforgot: '',

View File

@@ -0,0 +1 @@
export {default as Messages} from './messages'

View File

@@ -0,0 +1,33 @@
.messages_page{
margin-left: auto;
margin-right: auto;
margin-top: auto;
margin-bottom: auto;
min-height: 400px;
}
.title_msg{
font-weight: bold;
}
.user{
font-weight: bold;
}
.active-user{
color:blue;
background-color: rgba(174, 189, 241, 0.71);
border-radius: 1rem !important;
}
.chat-list{
border-radius: 20px;
}
.chat_dest{
}
.chat_my{
}

View File

@@ -0,0 +1,103 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { toolsext } from '../../store/Modules/toolsext'
import { MessageStore, UserStore } from '../../store/Modules'
import globalroutines from '../../globalroutines/index'
import { tools } from '../../store/Modules/tools'
import MixinUsers from '../../mixins/mixin-users'
import { IChat, IMessage, IUserState } from '../../model'
import { Getter } from 'vuex-class'
import { IMsgUsers } from '../../model/MessageStore'
// import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'
const namespace = 'MessageModule'
@Component({
name: 'Messages',
mixins: [MixinUsers],
components: { }
})
export default class Messages extends Vue {
public $t
public $q
public mydrawer = true
public miniState = false
public chatsel: IChat = {
username: '',
lasttimeActive: new Date()
}
@Getter('getlasts_messages', { namespace })
public lasts_messages: (state: IUserState) => IMessage[]
public showNotif(msgcode) {
tools.showNotif(this.$q, this.$t(msgcode))
}
public drawerClick(e) {
// if in "mini" state and user
// click on drawer, we switch it to "normal" mode
if (this.miniState) {
this.miniState = false
// notice we have registered an event with capture flag;
// we need to stop further propagation as this click is
// intended for switching drawer to "normal" mode only
e.stopPropagation()
}
}
get getheight() {
// return height()
return this.$q.screen.height - 43 // .toolbar
}
public isMenuActive(username) {
return this.chatsel.username === username
}
@Watch('$route.params.un')
public changeusername() {
this.chatsel.username = this.$route.params.un
if (!this.miniState && tools.isMobile()) {
this.miniState = true
}
// Retrieve last msgs data from the server
MessageStore.actions.updateMsgDataFromServer({username: this.chatsel.username, lastdataread: this.getlastdataread() } )
}
public selChat(mymsg: IMessage) {
this.$router.replace('/messages/' + mymsg.dest.username)
}
public msgchat(): IMsgUsers {
// Get msg for this chat
return MessageStore.state.users_msg.find((rec) => rec.username === this.chatsel.username)
}
public msgchat_records(): IMessage[] {
const myrec = this.msgchat()
console.log('myrec', myrec)
// Get msg for this chat
return (myrec) ? myrec.msgs : []
}
public getlastdataread(): Date {
const myrec = this.msgchat()
// Get msg for this chat
return (myrec) ? tools.gettimestampByDate(myrec.lastdataread) : tools.getLastDateReadReset()
}
public getMsgText(msg: IMessage) {
return [msg.message]
}
public created() {
this.changeusername()
}
}

View File

@@ -0,0 +1,136 @@
<template>
<div>
<q-layout view="hHh Lpr lff" container :style="`height: ` + getheight + `px`"
class="shadow-2 rounded-borders messages_page">
<q-drawer
v-model="mydrawer"
:mini="!mydrawer || miniState"
@click.capture="drawerClick"
:width="300"
:breakpoint="300"
bordered
content-class="bg-grey-3">
<q-scroll-area class="fit">
<q-list bordered class="rounded-borders chat-list">
<q-item-label header class="title_msg">{{$t('msgs.messages')}}</q-item-label>
<q-separator/>
<div v-if="getNumMsg === 0">
<q-item>
{{$t('msgs.nomessage')}}
</q-item>
</div>
<q-item clickable
:active="isMenuActive(msg.dest.username)"
active-class="active-user"
v-for="(msg, index) in lasts_messages()"
:key="index"
@click="selChat(msg)">
<q-item-section avatar>
<q-avatar>
<img :src="getImgByUsername(msg.dest.username)">
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label lines="1">{{getUserByUsername(msg.dest.username)}}</q-item-label>
<q-item-label caption lines="2">
{{msg.message}}
</q-item-label>
</q-item-section>
<q-item-section side top>
{{tools.getstrDateTimeShort(msg.datemsg)}}
</q-item-section>
</q-item>
<q-separator/>
</q-list>
</q-scroll-area>
<div class="q-mini-drawer-hide absolute" style="top: 15px; right: -17px">
<q-btn
dense
round
unelevated
color="accent"
icon="chevron_left"
@click="miniState = true">
</q-btn>
</div>
</q-drawer>
<q-page-container>
<q-page class="q-px-lg q-py-md">
<div>
<q-item clickable v-if="!!chatsel.username">
<q-item-section avatar>
<q-avatar>
<img :src="getImgByUsername(chatsel.username)">
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label lines="1">{{getUserByUsername(chatsel.username)}}</q-item-label>
<q-item-label caption lines="2">
{{func_tools.getDateTimeShortStr(chatsel.lasttimeActive)}}
</q-item-label>
</q-item-section>
</q-item>
</div>
<q-separator/>
<div class="q-pa-md row" style="flex-direction: column;">
<q-item clickable v-for="(msg, index) in msgchat_records()" :key="index" v-if="msg.dest">
<div class="chat_dest" v-if="msg.dest.username === getMyUsername()">
<q-chat-message
:name="getUserByUsername(msg.origin.username)"
:text="getMsgText(msg)"
:stamp="tools.getstrDateTimeShort(msg.datemsg)"
text-color="black"
bg-color="grey-2">
<template v-slot:avatar>
<q-avatar size="sm">
<img :src="getImgByUsername(msg.origin.username)">
</q-avatar>
</template>
</q-chat-message>
</div>
<div class="chat_my" v-else>
<q-chat-message
name="me"
:text="getMsgText(msg)"
:stamp="tools.getstrDateTimeShort(msg.datemsg)"
sent
bg-color="blue-2">
<template v-slot:avatar>
<q-avatar size="sm">
<img :src="getMyImg">
</q-avatar>
</template>
</q-chat-message>
</div>
</q-item>
</div>
</q-page>
</q-page-container>
</q-layout>
</div>
</template>
<script lang="ts" src="./messages.ts">
</script>
<style lang="scss" scoped>
@import './messages.scss';
</style>