Feat: Show notes panel on crm page (#2320)
* Feat: Show notes panel on CRM page Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
committed by
GitHub
parent
75d05e55ae
commit
fe2af370e0
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<note-list :notes="notes" @add="onAdd" @delete="onDelete" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NoteList from './components/NoteList';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NoteList,
|
||||
},
|
||||
props: {
|
||||
contactId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
notes() {
|
||||
return this.$store.getters['contactNotes/getAllNotesByContact'](
|
||||
this.contactId
|
||||
);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchContactNotes();
|
||||
},
|
||||
methods: {
|
||||
fetchContactNotes() {
|
||||
const { contactId } = this;
|
||||
if (contactId) this.$store.dispatch('contactNotes/get', { contactId });
|
||||
},
|
||||
onAdd(content) {
|
||||
const { contactId } = this;
|
||||
this.$store.dispatch('contactNotes/create', { content, contactId });
|
||||
},
|
||||
onDelete(noteId) {
|
||||
const { contactId } = this;
|
||||
this.$store.dispatch('contactNotes/delete', { noteId, contactId });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<textarea
|
||||
v-model="inputText"
|
||||
:placeholder="$t('NOTES.ADD.PLACEHOLDER')"
|
||||
class="input--note"
|
||||
@keydown.enter.shift.exact="onAdd"
|
||||
/>
|
||||
<div class="footer">
|
||||
<woot-button
|
||||
size="tiny"
|
||||
color-scheme="warning"
|
||||
:title="$t('NOTES.ADD.TITLE')"
|
||||
:is-disabled="buttonDisabled"
|
||||
@click="onAdd"
|
||||
>
|
||||
{{ $t('NOTES.ADD.BUTTON') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
inputText: '',
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
buttonDisabled() {
|
||||
return this.inputText === '';
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onAdd() {
|
||||
if (this.inputText !== '') {
|
||||
this.$emit('add', this.inputText);
|
||||
}
|
||||
this.inputText = '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.input--note {
|
||||
font-size: var(--font-size-mini);
|
||||
border-color: transparent;
|
||||
margin-bottom: var(--space-small);
|
||||
padding: 0;
|
||||
resize: none;
|
||||
min-height: var(--space-larger);
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="card note-wrap">
|
||||
<p class="note__content">
|
||||
{{ note }}
|
||||
</p>
|
||||
<div class="footer">
|
||||
<div class="meta">
|
||||
<div :title="userName">
|
||||
<thumbnail :src="thumbnail" :username="userName" size="16px" />
|
||||
</div>
|
||||
<div class="date-wrap">
|
||||
<span>{{ readableTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<woot-button
|
||||
variant="smooth"
|
||||
size="tiny"
|
||||
icon="ion-compose"
|
||||
color-scheme="secondary"
|
||||
@click="onEdit"
|
||||
/>
|
||||
<woot-button
|
||||
variant="smooth"
|
||||
size="tiny"
|
||||
icon="ion-trash-b"
|
||||
color-scheme="secondary"
|
||||
@click="onDelete"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
import timeMixin from 'dashboard/mixins/time';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Thumbnail,
|
||||
},
|
||||
|
||||
mixins: [timeMixin],
|
||||
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
userName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
timeStamp: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
thumbnail: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
readableTime() {
|
||||
return this.dynamicTime(this.timeStamp);
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onEdit() {
|
||||
this.$emit('edit', this.id);
|
||||
},
|
||||
onDelete() {
|
||||
this.$emit('delete', this.id);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.note__content {
|
||||
font-size: var(--font-size-mini);
|
||||
margin-bottom: var(--space-smaller);
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
padding: var(--space-smaller) 0;
|
||||
|
||||
.date-wrap {
|
||||
margin-left: var(--space-smaller);
|
||||
padding: var(--space-micro);
|
||||
color: var(--color-body);
|
||||
font-size: var(--font-size-micro);
|
||||
}
|
||||
}
|
||||
.actions {
|
||||
display: flex;
|
||||
visibility: hidden;
|
||||
|
||||
.button {
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.note-wrap:hover {
|
||||
.actions {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="notelist-wrap">
|
||||
<h3 class="block-title">
|
||||
{{ $t('NOTES.HEADER.TITLE') }}
|
||||
</h3>
|
||||
<add-note @add="onAddNote" />
|
||||
<contact-note
|
||||
v-for="note in notes"
|
||||
:id="note.id"
|
||||
:key="note.id"
|
||||
:note="note.content"
|
||||
:user-name="note.user.name"
|
||||
:time-stamp="note.created_at"
|
||||
:thumbnail="note.user.thumbnail"
|
||||
@edit="onEditNote"
|
||||
@delete="onDeleteNote"
|
||||
/>
|
||||
<div class="button-wrap">
|
||||
<woot-button variant="link" @click="onclick">
|
||||
{{ $t('NOTES.FOOTER.BUTTON') }}
|
||||
<i class="ion-arrow-right-c" />
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ContactNote from './ContactNote';
|
||||
import AddNote from './AddNote';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ContactNote,
|
||||
AddNote,
|
||||
},
|
||||
|
||||
props: {
|
||||
notes: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onclick() {
|
||||
this.$emit('show');
|
||||
},
|
||||
onAddNote(value) {
|
||||
this.$emit('add', value);
|
||||
},
|
||||
onEditNote(value) {
|
||||
this.$emit('edit', value);
|
||||
},
|
||||
onDeleteNote(value) {
|
||||
this.$emit('delete', value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.button-wrap {
|
||||
margin-top: var(--space-one);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,19 @@
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import AddNote from '../components/AddNote.vue';
|
||||
|
||||
export default {
|
||||
title: 'Components/Notes/Add',
|
||||
component: AddNote,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { AddNote },
|
||||
template: '<add-note v-bind="$props" @add="onAdd"></add-note>',
|
||||
});
|
||||
|
||||
export const Add = Template.bind({});
|
||||
Add.args = {
|
||||
onAdd: action('Added'),
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import ContactNote from '../components/ContactNote.vue';
|
||||
|
||||
export default {
|
||||
title: 'Components/Notes/Note',
|
||||
component: ContactNote,
|
||||
argTypes: {
|
||||
id: {
|
||||
control: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
note: {
|
||||
defaultValue:
|
||||
'A copy and paste musical notes symbols & music symbols collection for easy access.',
|
||||
control: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
userName: {
|
||||
defaultValue: 'John Doe',
|
||||
control: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
timeStamp: {
|
||||
defaultValue: 1618046084,
|
||||
control: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
thumbnail: {
|
||||
defaultValue: 'https://randomuser.me/api/portraits/men/62.jpg',
|
||||
control: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { ContactNote },
|
||||
template:
|
||||
'<contact-note v-bind="$props" @edit="onEdit" @delete="onDelete"></contact-note>',
|
||||
});
|
||||
|
||||
export const Note = Template.bind({});
|
||||
Note.args = {
|
||||
onEdit: action('Edit'),
|
||||
onDelete: action('Delete'),
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import NoteList from '../components/NoteList';
|
||||
|
||||
export default {
|
||||
title: 'Components/Notes/List',
|
||||
component: NoteList,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
const Template = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: { NoteList },
|
||||
template:
|
||||
'<note-list v-bind="$props" @addNote="onAddNote" @editNote="onEditNote" @deleteNote="onDeleteNote" @show="onClick"></note-list>',
|
||||
});
|
||||
|
||||
export const List = Template.bind({});
|
||||
List.args = {
|
||||
onClick: action('show'),
|
||||
onAddNote: action('added'),
|
||||
onEditNote: action('edit'),
|
||||
onDeleteNote: action('deleted'),
|
||||
notes: [
|
||||
{
|
||||
id: '12345',
|
||||
content:
|
||||
'It is a long established fact that a reader will be distracted.',
|
||||
user: {
|
||||
name: 'John Doe',
|
||||
thumbnail: 'https://randomuser.me/api/portraits/men/69.jpg',
|
||||
},
|
||||
created_at: 1618046084,
|
||||
},
|
||||
{
|
||||
id: '12346',
|
||||
content:
|
||||
'It is simply dummy text of the printing and typesetting industry.',
|
||||
user: {
|
||||
name: 'Pearl Cruz',
|
||||
thumbnail: 'https://randomuser.me/api/portraits/women/29.jpg',
|
||||
},
|
||||
created_at: 1616046076,
|
||||
},
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user