refactor: replace custom CRM with Monica fork
Some checks failed
Build & Push Monica Image to Gitea Registry / build-and-push (push) Failing after 9s
Some checks failed
Build & Push Monica Image to Gitea Registry / build-and-push (push) Failing after 9s
This commit is contained in:
237
resources/js/components/people/activity/ActivityList.vue
Normal file
237
resources/js/components/people/activity/ActivityList.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<style scoped>
|
||||
.btn-title {
|
||||
top: -7px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="">
|
||||
<h3 class="mb2">
|
||||
🍿 {{ $t('people.activity_title') }}
|
||||
|
||||
<span class="fr relative btn-title">
|
||||
<a v-if="displayLogActivity === false" v-cy-name="'add-activity-button'" class="btn edit-information" @click="displayLogActivity = true">
|
||||
{{ $t('people.activities_add_activity') }}
|
||||
</a>
|
||||
<a v-else class="btn edit-information" @click="displayLogActivity = false">
|
||||
{{ $t('app.cancel') }}
|
||||
</a>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<!-- BLANK STATE -->
|
||||
<div v-if="!displayLogActivity && activities.length === 0" class="w-100">
|
||||
<div v-cy-name="'activities-blank-state'" class="bg-near-white tc pa3 br2 ba b--light-gray">
|
||||
<p>{{ $t('people.activities_blank_title', { name: name }) }}</p>
|
||||
<a class="pointer" href="" @click.prevent="displayLogActivity = true">
|
||||
{{ $t('people.activities_blank_add_activity') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LOG AN ACTIVITY -->
|
||||
<template v-if="displayLogActivity">
|
||||
<create-activity
|
||||
:hash="hash"
|
||||
:contact-id="contactId"
|
||||
:name="name"
|
||||
@update="updateList($event)"
|
||||
@cancel="displayLogActivity = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- LIST OF ACTIVITIES -->
|
||||
<div v-cy-name="'activities-body'" v-cy-items="activities.map(c => c.id)">
|
||||
<div v-for="activity in activities" :key="activity.id" v-cy-name="'activity-body-'+activity.id" class="ba br2 b--black-10 br--top w-100 mb2">
|
||||
<template v-if="!activity.edit">
|
||||
<h2 class="pl2 pr2 pt3 f5">
|
||||
{{ activity.summary }}
|
||||
</h2>
|
||||
|
||||
<div v-if="activity.description" dir="auto" class="markdown pl2 pr2 pb3" v-html="compiledMarkdown(activity.description)">
|
||||
</div>
|
||||
|
||||
<!-- DETAILS -->
|
||||
<div class="pa2 cf bt b--black-10 br--bottom f7">
|
||||
<div class="w-70" :class="[ dirltr ? 'fl' : 'fr' ]">
|
||||
<ul class="list">
|
||||
<!-- HAPPENED AT -->
|
||||
<li class="di" :class="[ dirltr ? 'mr3' : 'ml3' ]">
|
||||
{{ activity.happened_at | moment }}
|
||||
</li>
|
||||
|
||||
<!-- PARTICIPANT LIST -->
|
||||
<li v-if="activity.attendees.total > 1" class="di">
|
||||
<ul class="di list" :class="[ dirltr ? 'mr3' : 'ml3' ]">
|
||||
<li class="di">
|
||||
{{ $t('people.activities_list_participants', { total: activity.attendees.total - 1}) }}
|
||||
</li>
|
||||
<li v-for="attendee in activity.attendees.contacts.filter(c => c.id !== contactId)" :key="attendee.id" class="di mr2">
|
||||
<a :href="'people/' + attendee.hash_id">{{ attendee.complete_name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<!-- EMOTIONS LIST -->
|
||||
<li v-if="activity.emotions.length !== 0" class="di">
|
||||
<ul class="di list" :class="[ dirltr ? 'mr3' : 'ml3' ]">
|
||||
<li class="di">
|
||||
{{ $t('people.activities_list_emotions') }}
|
||||
</li>
|
||||
<li v-for="emotion in activity.emotions" :key="emotion.id" class="di">
|
||||
{{ $t('app.emotion_' + emotion.name) }}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<!-- ACTIVITY TYPE -->
|
||||
<li v-if="activity.activity_type" class="di" :class="[ dirltr ? 'mr3' : 'ml3' ]">
|
||||
{{ activity.activity_type.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="w-30" :class="[ dirltr ? 'fl tr' : 'fr tl' ]">
|
||||
<!-- ACTIONS -->
|
||||
<ul class="list">
|
||||
<li class="di">
|
||||
<a v-cy-name="'edit-activity-button-'+activity.id" href="" class="pointer" @click.prevent="$set(activity, 'edit', true)">{{ $t('app.edit') }}</a>
|
||||
<a v-show="destroyActivityId !== activity.id" v-cy-name="'delete-activity-button-'+activity.id" href="" class="pointer" @click.prevent="showDestroyActivity(activity)">{{ $t('app.delete') }}</a>
|
||||
<ul v-show="destroyActivityId === activity.id" class="di">
|
||||
<li class="di">
|
||||
<a v-cy-name="'confirm-delete-activity'" class="pointer red" @click.prevent="destroyActivity(activity)">
|
||||
{{ $t('app.delete_confirm') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="di">
|
||||
<a class="pointer mr1" @click.prevent="destroyActivityId = 0">
|
||||
{{ $t('app.cancel') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- EDIT THE CURRENT ACTIVITY -->
|
||||
<create-activity v-else
|
||||
:hash="hash"
|
||||
:name="name"
|
||||
:activity="activity"
|
||||
:contact-id="contactId"
|
||||
@update="$set(activity, 'edit', false); updateList($event)"
|
||||
@cancel="$set(activity, 'edit', false); displayLogActivity = false"
|
||||
/>
|
||||
</div>
|
||||
<a v-if="!isLastPage" class="pointer mr1" style="float: right" @click.prevent="getActivities">
|
||||
{{ $t('app.load_more') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p v-if="activities.length > 0" class="tc">
|
||||
📗 <a :href="'people/' + hash + '/activities/summary'">{{ $t('people.activities_view_activities_report') }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import CreateActivity from './CreateActivity.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CreateActivity
|
||||
},
|
||||
|
||||
filters: {
|
||||
moment: function (date) {
|
||||
return moment.utc(date).format('LL');
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
hash: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
contactId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
displayLogActivity: false,
|
||||
activities: [],
|
||||
emotions: [],
|
||||
displayDescription: false,
|
||||
displayEmotions: false,
|
||||
displayCategory: false,
|
||||
displayParticipants: false,
|
||||
destroyActivityId: 0,
|
||||
errors: [],
|
||||
currentPage: 0,
|
||||
lastPage: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
dirltr() {
|
||||
return this.$root.htmldir === 'ltr';
|
||||
},
|
||||
isLastPage () {
|
||||
return this.lastPage === this.currentPage;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.prepareComponent();
|
||||
},
|
||||
|
||||
methods: {
|
||||
prepareComponent() {
|
||||
this.getActivities();
|
||||
this.todayDate = moment().format('YYYY-MM-DD');
|
||||
},
|
||||
|
||||
compiledMarkdown (text) {
|
||||
return text !== undefined && text !== null ? marked(text, { sanitize: true }) : '';
|
||||
},
|
||||
|
||||
getActivities() {
|
||||
this.currentPage++;
|
||||
axios.get('api/contacts/' + this.contactId + '/activities?page=' + this.currentPage)
|
||||
.then(response => {
|
||||
this.activities.push(...response.data.data);
|
||||
this.currentPage = response.data.meta.current_page;
|
||||
this.lastPage = response.data.meta.last_page;
|
||||
});
|
||||
},
|
||||
|
||||
updateList(activity) {
|
||||
this.displayLogActivity = false;
|
||||
const index = this.activities.indexOf(this.activities.find(item => item.id === activity.id));
|
||||
Vue.set(this.activities, index >= 0 ? index : this.activities.length, activity);
|
||||
},
|
||||
|
||||
showDestroyActivity(activity) {
|
||||
this.destroyActivityId = activity.id;
|
||||
},
|
||||
|
||||
destroyActivity(activity) {
|
||||
axios.delete(`activities/${activity.id}`)
|
||||
.then(response => {
|
||||
this.activities.splice(this.activities.indexOf(activity), 1);
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
58
resources/js/components/people/activity/ActivityTypeList.vue
Normal file
58
resources/js/components/people/activity/ActivityTypeList.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<form-select
|
||||
:id="'activity-type-list'"
|
||||
v-model="choosenCategory"
|
||||
:title="title"
|
||||
:options="activityCategories"
|
||||
:iclass="'br2 f5 w-100 ba b--black-40 pa2 outline-0'"
|
||||
@input="$emit('input', $event)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
choosenCategory: '',
|
||||
activityCategories: null,
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
value(val) {
|
||||
this.choosenCategory = val;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getActivities().then(() => {
|
||||
this.choosenCategory = this.value;
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
getActivities() {
|
||||
return axios.get('activityCategories')
|
||||
.then(response => {
|
||||
this.activityCategories = Object.assign({}, _.map(response.data, a => {
|
||||
return {
|
||||
name: a.name,
|
||||
options: a.types,
|
||||
};
|
||||
}));
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
297
resources/js/components/people/activity/CreateActivity.vue
Normal file
297
resources/js/components/people/activity/CreateActivity.vue
Normal file
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- LOG AN ACTIVITY -->
|
||||
<transition name="fade">
|
||||
<div class="ba br3 mb3 pa3 b--black-40">
|
||||
<div class="dt dt--fixed pb3 mb3 mb0-ns bb b--gray-monica">
|
||||
<!-- SUMMARY -->
|
||||
<div class="dtc pr2">
|
||||
<form-input
|
||||
:id="'summary'"
|
||||
v-model="newActivity.summary"
|
||||
:input-type="'text'"
|
||||
:title="$t('people.activities_add_title', { name: name })"
|
||||
:required="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- WHEN -->
|
||||
<div class="dtc">
|
||||
<p class="mb2 b">
|
||||
{{ $t('people.activities_add_date_occured') }}
|
||||
</p>
|
||||
<div class="di">
|
||||
<div class="dib">
|
||||
<form-date
|
||||
ref="date"
|
||||
v-model="newActivity.happened_at"
|
||||
:show-calendar-on-focus="true"
|
||||
:default-date="todayDate"
|
||||
:locale="locale"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ADDITIONAL FIELDS -->
|
||||
<div v-show="!displayDescription || !displayEmotions || !displayCategory || !displayParticipants" class="bb b--gray-monica pv3 mb3">
|
||||
<ul class="list">
|
||||
<li v-show="!displayDescription" class="di pointer mr3 nowrap-link">
|
||||
<a href="" @click.prevent="displayDescription = true">{{ $t('people.activities_add_more_details') }}</a>
|
||||
</li>
|
||||
<li v-show="!displayEmotions" class="di pointer mr3 nowrap-link">
|
||||
<a href="" @click.prevent="displayEmotions = true">{{ $t('people.activities_add_emotions') }}</a>
|
||||
</li>
|
||||
<li v-show="!displayCategory" class="di pointer mr3 nowrap-link">
|
||||
<a v-cy-name="'activities_add_category'" href="" @click.prevent="displayCategory = true">{{ $t('people.activities_add_category') }}</a>
|
||||
</li>
|
||||
<li v-show="!displayParticipants" class="di pointer nowrap-link">
|
||||
<a href="" @click.prevent="displayParticipants = true">{{ $t('people.activities_add_participants_cta') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- DESCRIPTION -->
|
||||
<div v-if="displayDescription" class="bb b--gray-monica pv3 mb3">
|
||||
<form-textarea
|
||||
v-model="newActivity.description"
|
||||
:required="true"
|
||||
:no-label="true"
|
||||
:rows="4"
|
||||
:title="$t('people.activities_summary')"
|
||||
:placeholder="$t('people.conversation_add_content')"
|
||||
@contentChange="updateDescription($event)"
|
||||
/>
|
||||
<p class="f6">
|
||||
{{ $t('app.markdown_description') }} <a href="https://guides.github.com/features/mastering-markdown/" rel="noopener noreferrer" target="_blank">
|
||||
{{ $t('app.markdown_link') }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- EMOTIONS -->
|
||||
<div v-if="displayEmotions" class="bb b--gray-monica pb3 mb3">
|
||||
<label>
|
||||
{{ $t('people.activities_add_emotions_title') }}
|
||||
</label>
|
||||
<emotion
|
||||
class="pv2"
|
||||
:initial-emotions="initialEmotions"
|
||||
@update="updateEmotionsList"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- ACTIVITY CATEGORIES -->
|
||||
<div v-if="displayCategory" class="bb b--gray-monica pb3 mb3">
|
||||
<activity-type-list
|
||||
v-model="newActivity.activity_type_id"
|
||||
:title="$t('people.activities_add_pick_activity')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- PARTICPANTS -->
|
||||
<div v-if="displayParticipants" class="bb b--gray-monica pb3 mb3">
|
||||
<label>
|
||||
{{ $t('people.activities_add_participants', {name: name}) }}
|
||||
</label>
|
||||
<participant
|
||||
:hash="hash"
|
||||
:initial-participants="participants"
|
||||
@update="updateParticipant($event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<error :errors="errors" />
|
||||
|
||||
<!-- ACTIONS -->
|
||||
<div class="pt3">
|
||||
<div class="flex-ns justify-between">
|
||||
<div class="">
|
||||
<a class="btn btn-secondary tc w-auto-ns w-100 mb2 pb0-ns" @click.prevent="close()">
|
||||
{{ $t('app.cancel') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="">
|
||||
<button v-cy-name="'save-activity-button'" class="btn btn-primary w-auto-ns w-100 mb2 pb0-ns" @click.prevent="store()">
|
||||
{{ activity ? $t('app.save') : $t('app.add') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import ActivityTypeList from './ActivityTypeList.vue';
|
||||
import Emotion from '../Emotion.vue';
|
||||
import Error from '../../partials/Error.vue';
|
||||
import Participant from '../Participant.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActivityTypeList,
|
||||
Emotion,
|
||||
Error,
|
||||
Participant,
|
||||
},
|
||||
|
||||
filters: {
|
||||
moment: function (date) {
|
||||
return moment.utc(date).format('LL');
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
hash: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
contactId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
activity: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
displayDescription: false,
|
||||
displayEmotions: false,
|
||||
displayCategory: false,
|
||||
displayParticipants: false,
|
||||
newActivity: {
|
||||
summary: '',
|
||||
description: '',
|
||||
happened_at: '',
|
||||
emotions: [],
|
||||
activity_type_id: null,
|
||||
contacts: [],
|
||||
},
|
||||
todayDate: '',
|
||||
initialEmotions: [],
|
||||
participants: [],
|
||||
errors: [],
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
locale() {
|
||||
return this.$root.locale;
|
||||
},
|
||||
|
||||
dirltr() {
|
||||
return this.$root.htmldir === 'ltr';
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
participants(value) {
|
||||
this.newActivity.contacts = _.map(value, p => p.id);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.prepareComponent();
|
||||
},
|
||||
|
||||
methods: {
|
||||
prepareComponent() {
|
||||
this.todayDate = moment().format('YYYY-MM-DD');
|
||||
this.resetFields();
|
||||
},
|
||||
|
||||
updateDescription(updatedDescription) {
|
||||
this.newActivity.description = updatedDescription;
|
||||
},
|
||||
|
||||
resetFields() {
|
||||
if (this.activity) {
|
||||
this.initialEmotions = JSON.parse(JSON.stringify(this.activity.emotions));
|
||||
this.newActivity.summary = this.activity.summary;
|
||||
this.newActivity.description = this.activity.description;
|
||||
this.newActivity.happened_at = this.activity.happened_at;
|
||||
this.updateEmotionsList(this.activity.emotions);
|
||||
this.newActivity.activity_type_id = this.activity.activity_type ? this.activity.activity_type.id : null;
|
||||
this.participants = this.activity.attendees.contacts.map(attendee => {
|
||||
return {
|
||||
id: attendee.id,
|
||||
name: attendee.complete_name,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
this.initialEmotions = [];
|
||||
this.newActivity.summary = '';
|
||||
this.newActivity.description = '';
|
||||
this.newActivity.happened_at = this.todayDate;
|
||||
this.newActivity.emotions = [];
|
||||
this.newActivity.activity_type_id = null;
|
||||
this.participants = [];
|
||||
}
|
||||
this.displayDescription = this.newActivity.description ? this.newActivity.description !== '' : false;
|
||||
this.displayEmotions = this.newActivity.emotions && this.newActivity.emotions.length > 0;
|
||||
this.displayCategory = this.newActivity.activity_type_id !== null;
|
||||
this.displayParticipants = this.participants.length > 0;
|
||||
this.errors = [];
|
||||
},
|
||||
|
||||
close() {
|
||||
this.resetFields();
|
||||
this.$emit('cancel');
|
||||
},
|
||||
|
||||
store() {
|
||||
const method = this.activity ? 'put' : 'post';
|
||||
const url = this.activity ? 'activities/'+this.activity.id : 'activities';
|
||||
|
||||
if (! this.newActivity.contacts.includes(this.contactId)) {
|
||||
this.newActivity.contacts.push(this.contactId);
|
||||
}
|
||||
|
||||
axios[method](url, this.newActivity)
|
||||
.then(response => {
|
||||
this.resetFields();
|
||||
this.$emit('update', response.data.data);
|
||||
|
||||
this.$notify({
|
||||
group: 'main',
|
||||
title: this.$t('people.activities_add_success'),
|
||||
text: '',
|
||||
type: 'success'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this._errorHandle(error);
|
||||
});
|
||||
},
|
||||
|
||||
updateParticipant: function (participants) {
|
||||
this.participants = participants;
|
||||
},
|
||||
|
||||
updateEmotionsList: function(emotions) {
|
||||
// filter the list of emotions to populate a new array
|
||||
// containing only the emotion ids and not the entire objetcs
|
||||
this.newActivity.emotions = _.map(emotions, emotion => emotion.id);
|
||||
},
|
||||
|
||||
_errorHandle(error) {
|
||||
if (error.response && typeof error.response.data === 'object') {
|
||||
this.errors = _.flatten(_.toArray(error.response.data));
|
||||
} else {
|
||||
this.errors = [this.$t('app.error_try_again'), error.message];
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user