diff options
Diffstat (limited to 'plugins/Feedback/vue/src')
6 files changed, 224 insertions, 94 deletions
diff --git a/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.adapter.ts b/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.adapter.ts new file mode 100644 index 0000000000..8206972ef7 --- /dev/null +++ b/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.adapter.ts @@ -0,0 +1,19 @@ +/*! + * Matomo - free/libre analytics platform + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +import { createAngularJsAdapter } from 'CoreHome'; +import RateFeature from './FeedbackQuestion.vue'; + +export default createAngularJsAdapter({ + component: RateFeature, + scope: { + showQuestionBanner: { + angularJsBind: '@', + }, + }, + directiveName: 'piwikFeedbackQuestion', +}); diff --git a/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.less b/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.less new file mode 100644 index 0000000000..1d65d14b05 --- /dev/null +++ b/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.less @@ -0,0 +1,34 @@ +.bannerHeader { + min-height: 48px; + background-color: #263238; + text-align: center; + color: #fff; + + span { + vertical-align: sub; + font-size: 14px; + } + + a { + margin-left: 16px; + margin-top: 6px; + } + + .close-btn { + float: right; + margin-right: 20px; + font-size: 1.2em; + margin-top: 12px; + } +} + +.modal { + .has-error { + border: 1px red solid; + } + + .error-text { + float: left; + color: red; + } +}
\ No newline at end of file diff --git a/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.vue b/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.vue new file mode 100644 index 0000000000..52fa9cd9fa --- /dev/null +++ b/plugins/Feedback/vue/src/FeedbackQuestion/FeedbackQuestion.vue @@ -0,0 +1,169 @@ +<!-- + Matomo - free/libre analytics platform + @link https://matomo.org + @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later +--> + +<template> + <div> + <div v-if="!isHidden" class="bannerHeader"> + <span>{{ translate(`Feedback_FeedbackTitle`) }} <i class="icon-heart red-text"></i></span> + <a @click="showQuestion" class="btn"> + {{ translate(`Feedback_Question${question}`) }} + </a> + <a class="close-btn" @click="disableReminder"> + <i class="icon-close white-text"></i></a> + </div> + <div class="ratefeature"> + <MatomoDialog + v-model="showFeedbackForm" + @validation="sendFeedback()" + > + <div + class="ui-confirm ratefeatureDialog" + > + <h2>{{ translate(`Feedback_Question${question}`) }}</h2> + <p + v-html="translate('Feedback_FeedbackSubtitle', + `<i class='icon-heart red-text'></i>`)"></p> + <br/> + <div class="messageContainer"> + <div class="error-text" v-if="errorMessage">{{ errorMessage }}</div> + <textarea id="message" :class="{'has-error':errorMessage}" v-model="feedbackMessage"/> + </div> + <br/> + <p + v-html="translate('Feedback_Policy',`<a rel='nofollow' href='https://matomo.org/privacy-policy/' target='_blank'>`,'</a>')"></p> + <input + type="button" + role="validation" + :value="translate('Feedback_SendFeedback')" + /> + <input + type="button" + role="cancel" + :value="translate('General_Cancel')" + /> + </div> + </MatomoDialog> + <MatomoDialog v-model="feedbackDone"> + <div + class="ui-confirm ratefeatureDialog" + > + <h2>{{ translate(`Feedback_ThankYou`) }}</h2> + <p v-html="translate('Feedback_ThankYourForFeedback', + `<i class='icon-heart red-text'></i>`)"> + </p> + <input + type="button" + role="cancel" + :value="translate('General_Close')" + /> + </div> + </MatomoDialog> + </div> + </div> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { + MatomoDialog, AjaxHelper, setCookie, getCookie, translate, +} from 'CoreHome'; + +const { $ } = window; + +const cookieName = 'feedback-question'; +export default defineComponent({ + + props: { + showQuestionBanner: String, + }, + components: { + MatomoDialog, + }, + computed: { + isHidden() { + if (this.showQuestionBanner === '0') { + return true; + } + return !!this.hide; + }, + }, + data() { + return { + questionText: '', + question: 0, + hide: null, + feedbackDone: false, + expanded: false, + showFeedbackForm: false, + feedbackMessage: null, + errorMessage: null, + }; + }, + watch: { + showFeedbackForm(val) { + // eslint-disable-next-line no-underscore-dangle + this.questionText = translate(`Feedback_Question${this.question}`); + if (val) { + setInterval(() => { + $('#message').focus(); + }, 500); + } + }, + }, + created() { + if (this.showQuestionBanner !== '0') { + this.initQuestion(); + } + }, + methods: { + initQuestion() { + if (!getCookie(cookieName)) { + this.question = this.getRandomIntBetween(0, 4); + } else { + // eslint-disable-next-line radix + this.question = parseInt(getCookie(cookieName)); + } + + const nextQuestion = (this.question + 1) % 4; + const sevenDays = 7 * 60 * 60 * 24 * 1000; + setCookie(cookieName, nextQuestion, sevenDays); + }, + getRandomIntBetween(min, max) { + // eslint-disable-next-line no-param-reassign + min = Math.ceil(min); + // eslint-disable-next-line no-param-reassign + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1) + min); + }, + showQuestion() { + this.showFeedbackForm = true; + this.errorMessage = null; + }, + disableReminder() { + AjaxHelper.fetch({ + method: 'Feedback.updateFeedbackReminderDate', + }); + this.hide = true; + }, + async sendFeedback() { + this.errorMessage = null; + const res = await AjaxHelper.fetch({ + method: 'Feedback.sendFeedbackForSurvey', + question: this.questionText, + message: this.feedbackMessage, + }); + + if (res.value === 'success') { + $('.modal').modal('close'); + this.feedbackDone = true; + this.hide = true; + } else { + this.errorMessage = res.value; + } + }, + }, +}); +</script> diff --git a/plugins/Feedback/vue/src/RateFeature/RateFeature.vue b/plugins/Feedback/vue/src/RateFeature/RateFeature.vue index 324142273f..ba90382e55 100644 --- a/plugins/Feedback/vue/src/RateFeature/RateFeature.vue +++ b/plugins/Feedback/vue/src/RateFeature/RateFeature.vue @@ -63,7 +63,6 @@ <div v-if="like" > - <ReviewLinks /> </div> <input type="button" @@ -78,7 +77,6 @@ <script lang="ts"> import { defineComponent } from 'vue'; import { MatomoDialog, AjaxHelper } from 'CoreHome'; -import ReviewLinks from '../ReviewLinks/ReviewLinks.vue'; export default defineComponent({ props: { @@ -86,7 +84,6 @@ export default defineComponent({ }, components: { MatomoDialog, - ReviewLinks, }, data() { return { diff --git a/plugins/Feedback/vue/src/ReviewLinks/ReviewLinks.vue b/plugins/Feedback/vue/src/ReviewLinks/ReviewLinks.vue deleted file mode 100644 index fa65f8569f..0000000000 --- a/plugins/Feedback/vue/src/ReviewLinks/ReviewLinks.vue +++ /dev/null @@ -1,90 +0,0 @@ -<!-- - Matomo - free/libre analytics platform - - @link https://matomo.org - @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later ---> - -<template> - <div class="requestReview"> - <p>{{ translate('Feedback_PleaseLeaveExternalReviewForMatomo') }}</p><br><br> - <div class="review-links"> - <div class="review-link"> - <a - href="https://www.capterra.com/p/182627/Matomo-Analytics/" - target="_blank" - > - <div class="image"> - <img - loading="lazy" - src="plugins/Feedback/images/capterra.svg" - /> - </div> - <div class="link">Capterra</div> - </a> - </div> - <div class="review-link"> - <a - href="https://www.g2crowd.com/products/matomo-formerly-piwik/details" - target="_blank" - > - <div class="image"> - <img - loading="lazy" - src="plugins/Feedback/images/g2crowd.svg" - /> - </div> - <div class="link">G2 Crowd</div> - </a> - </div> - <div class="review-link"> - <a - href="https://www.producthunt.com/posts/matomo-2" - target="_blank" - > - <div class="image"> - <img - loading="lazy" - src="plugins/Feedback/images/producthunt.svg" - /> - </div> - <div class="link">Product Hunt</div> - </a> - </div> - <div class="review-link"> - <a - href="https://www.saasworthy.com/product/matomo" - target="_blank" - > - <div class="image"> - <img - loading="lazy" - src="plugins/Feedback/images/saasworthy.png" - /> - </div> - <div class="link">SaaSworthy</div> - </a> - </div> - <div class="review-link"> - <a - href="https://www.trustradius.com/products/matomo/reviews" - target="_blank" - > - <div class="image"> - <img - loading="lazy" - src="plugins/Feedback/images/trustradius.svg" - /> - </div> - <div class="link">TrustRadius</div> - </a> - </div> - </div> - </div> -</template> - -<script lang="ts"> -import { defineComponent } from 'vue'; - -export default defineComponent({}); -</script> diff --git a/plugins/Feedback/vue/src/index.ts b/plugins/Feedback/vue/src/index.ts index 5f37c3b890..d4018200f8 100644 --- a/plugins/Feedback/vue/src/index.ts +++ b/plugins/Feedback/vue/src/index.ts @@ -6,6 +6,7 @@ */ import './RateFeature/RateFeature.adapter'; +import './FeedbackQuestion/FeedbackQuestion.adapter'; -export { default as ReviewLinks } from './ReviewLinks/ReviewLinks.vue'; export { default as RateFeature } from './RateFeature/RateFeature.vue'; +export { default as FeedbackQuestion } from './FeedbackQuestion/FeedbackQuestion.vue'; |