mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	chore: Add an indicator for incoming emails (#1112)
This commit is contained in:
		@@ -8,21 +8,9 @@
 | 
				
			|||||||
  font-weight: $font-weight-normal;
 | 
					  font-weight: $font-weight-normal;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .icon {
 | 
					 | 
				
			||||||
    bottom: $space-smaller;
 | 
					 | 
				
			||||||
    position: absolute;
 | 
					 | 
				
			||||||
    right: $space-small;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .message-text__wrap {
 | 
					  .message-text__wrap {
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .time {
 | 
					 | 
				
			||||||
      color: $color-primary-light;
 | 
					 | 
				
			||||||
      display: block;
 | 
					 | 
				
			||||||
      font-size: $font-size-micro;
 | 
					 | 
				
			||||||
      line-height: 1.8;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .link {
 | 
					    .link {
 | 
				
			||||||
      color: $color-white;
 | 
					      color: $color-white;
 | 
				
			||||||
@@ -37,24 +25,10 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .audio {
 | 
					 | 
				
			||||||
    .time {
 | 
					 | 
				
			||||||
      margin-top: -$space-two;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .image {
 | 
					  .image {
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .time {
 | 
					 | 
				
			||||||
      bottom: $space-smaller;
 | 
					 | 
				
			||||||
      color: $color-white;
 | 
					 | 
				
			||||||
      position: absolute;
 | 
					 | 
				
			||||||
      right: $space-small;
 | 
					 | 
				
			||||||
      white-space: nowrap;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .modal-container {
 | 
					    .modal-container {
 | 
				
			||||||
      text-align: center;
 | 
					      text-align: center;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -74,30 +48,6 @@
 | 
				
			|||||||
      width: 100%;
 | 
					      width: 100%;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  .map {
 | 
					 | 
				
			||||||
    @include flex;
 | 
					 | 
				
			||||||
    flex-direction: column;
 | 
					 | 
				
			||||||
    text-align: right;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    img {
 | 
					 | 
				
			||||||
      @include padding($space-small);
 | 
					 | 
				
			||||||
      max-height: 30rem;
 | 
					 | 
				
			||||||
      max-width: 20rem;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .time {
 | 
					 | 
				
			||||||
      @include padding($space-small);
 | 
					 | 
				
			||||||
      margin-left: -$space-smaller;
 | 
					 | 
				
			||||||
      margin-top: -$space-two;
 | 
					 | 
				
			||||||
      white-space: nowrap;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .locname {
 | 
					 | 
				
			||||||
      font-weight: $font-weight-medium;
 | 
					 | 
				
			||||||
      padding: $space-smaller;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.conversations-sidebar {
 | 
					.conversations-sidebar {
 | 
				
			||||||
@@ -257,14 +207,6 @@
 | 
				
			|||||||
      color: $color-body;
 | 
					      color: $color-body;
 | 
				
			||||||
      margin-right: auto;
 | 
					      margin-right: auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      .time {
 | 
					 | 
				
			||||||
        color: $color-light-gray;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      .image .time {
 | 
					 | 
				
			||||||
        color: $color-white;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      .link {
 | 
					      .link {
 | 
				
			||||||
        color: $color-primary-dark;
 | 
					        color: $color-primary-dark;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -321,10 +263,6 @@
 | 
				
			|||||||
          right: $space-one;
 | 
					          right: $space-one;
 | 
				
			||||||
          top: $space-smaller + $space-micro;
 | 
					          top: $space-smaller + $space-micro;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        .time {
 | 
					 | 
				
			||||||
          color: $color-light-gray;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -389,11 +327,6 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .time {
 | 
					 | 
				
			||||||
      color: $medium-gray;
 | 
					 | 
				
			||||||
      font-size: $font-size-micro;
 | 
					 | 
				
			||||||
      margin-left: $space-slab;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
        <bubble-text
 | 
					        <bubble-text
 | 
				
			||||||
          v-if="data.content"
 | 
					          v-if="data.content"
 | 
				
			||||||
          :message="message"
 | 
					          :message="message"
 | 
				
			||||||
 | 
					          :is-email="isEmailContentType"
 | 
				
			||||||
          :readable-time="readableTime"
 | 
					          :readable-time="readableTime"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <span v-if="hasAttachments">
 | 
					        <span v-if="hasAttachments">
 | 
				
			||||||
@@ -21,12 +22,10 @@
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
        <i
 | 
					        <bubble-actions
 | 
				
			||||||
          v-if="isPrivate"
 | 
					          :is-email="isEmailContentType"
 | 
				
			||||||
          v-tooltip.top-start="toolTipMessage"
 | 
					          :readable-time="readableTime"
 | 
				
			||||||
          class="icon ion-android-lock"
 | 
					          :is-private="data.private"
 | 
				
			||||||
          @mouseenter="isHovered = true"
 | 
					 | 
				
			||||||
          @mouseleave="isHovered = false"
 | 
					 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </p>
 | 
					      </p>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@@ -39,14 +38,16 @@ import timeMixin from '../../../mixins/time';
 | 
				
			|||||||
import BubbleText from './bubble/Text';
 | 
					import BubbleText from './bubble/Text';
 | 
				
			||||||
import BubbleImage from './bubble/Image';
 | 
					import BubbleImage from './bubble/Image';
 | 
				
			||||||
import BubbleFile from './bubble/File';
 | 
					import BubbleFile from './bubble/File';
 | 
				
			||||||
 | 
					import contentTypeMixin from 'shared/mixins/contentTypeMixin';
 | 
				
			||||||
 | 
					import BubbleActions from './bubble/Actions';
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
 | 
					    BubbleActions,
 | 
				
			||||||
    BubbleText,
 | 
					    BubbleText,
 | 
				
			||||||
    BubbleImage,
 | 
					    BubbleImage,
 | 
				
			||||||
    BubbleFile,
 | 
					    BubbleFile,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  mixins: [timeMixin, messageFormatterMixin],
 | 
					  mixins: [timeMixin, messageFormatterMixin, contentTypeMixin],
 | 
				
			||||||
  props: {
 | 
					  props: {
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
      type: Object,
 | 
					      type: Object,
 | 
				
			||||||
@@ -62,6 +63,12 @@ export default {
 | 
				
			|||||||
    message() {
 | 
					    message() {
 | 
				
			||||||
      return this.formatMessage(this.data.content);
 | 
					      return this.formatMessage(this.data.content);
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    contentType() {
 | 
				
			||||||
 | 
					      const {
 | 
				
			||||||
 | 
					        data: { content_type: contentType },
 | 
				
			||||||
 | 
					      } = this;
 | 
				
			||||||
 | 
					      return contentType;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    alignBubble() {
 | 
					    alignBubble() {
 | 
				
			||||||
      return !this.data.message_type ? 'left' : 'right';
 | 
					      return !this.data.message_type ? 'left' : 'right';
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -82,14 +89,6 @@ export default {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    isPrivate() {
 | 
					 | 
				
			||||||
      return this.data.private;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    toolTipMessage() {
 | 
					 | 
				
			||||||
      return this.data.private
 | 
					 | 
				
			||||||
        ? { content: this.$t('CONVERSATION.VISIBLE_TO_AGENTS'), classes: 'top' }
 | 
					 | 
				
			||||||
        : false;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    sentByMessage() {
 | 
					    sentByMessage() {
 | 
				
			||||||
      const { sender } = this.data;
 | 
					      const { sender } = this.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -109,7 +108,7 @@ export default {
 | 
				
			|||||||
    bubbleClass() {
 | 
					    bubbleClass() {
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        bubble: this.isBubble,
 | 
					        bubble: this.isBubble,
 | 
				
			||||||
        'is-private': this.isPrivate,
 | 
					        'is-private': this.data.private,
 | 
				
			||||||
        'is-image': this.hasImageAttachment,
 | 
					        'is-image': this.hasImageAttachment,
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -119,13 +118,10 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
<style lang="scss" scoped>
 | 
					<style lang="scss">
 | 
				
			||||||
@import '~dashboard/assets/scss/variables.scss';
 | 
					.wrap > .is-image.bubble {
 | 
				
			||||||
.wrap {
 | 
					 | 
				
			||||||
  .is-image {
 | 
					 | 
				
			||||||
  padding: 0;
 | 
					  padding: 0;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .image {
 | 
					  .image {
 | 
				
			||||||
    max-width: 32rem;
 | 
					    max-width: 32rem;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="message-text--metadata">
 | 
				
			||||||
 | 
					    <span class="time">{{ readableTime }}</span>
 | 
				
			||||||
 | 
					    <i
 | 
				
			||||||
 | 
					      v-if="isEmail"
 | 
				
			||||||
 | 
					      v-tooltip.top-start="$t('CHAT_LIST.RECEIVED_VIA_EMAIL')"
 | 
				
			||||||
 | 
					      class="ion ion-android-mail"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					    <i
 | 
				
			||||||
 | 
					      v-if="isPrivate"
 | 
				
			||||||
 | 
					      v-tooltip.top-start="$t('CONVERSATION.VISIBLE_TO_AGENTS')"
 | 
				
			||||||
 | 
					      class="icon ion-android-lock"
 | 
				
			||||||
 | 
					      @mouseenter="isHovered = true"
 | 
				
			||||||
 | 
					      @mouseleave="isHovered = false"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    readableTime: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: '',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isEmail: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isPrivate: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					.right {
 | 
				
			||||||
 | 
					  .message-text--metadata {
 | 
				
			||||||
 | 
					    .time {
 | 
				
			||||||
 | 
					      color: var(--w-100);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.left {
 | 
				
			||||||
 | 
					  .message-text--metadata {
 | 
				
			||||||
 | 
					    .time {
 | 
				
			||||||
 | 
					      color: var(--s-400);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.message-text--metadata {
 | 
				
			||||||
 | 
					  align-items: flex-end;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .time {
 | 
				
			||||||
 | 
					    margin-right: var(--space-small);
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    font-size: var(--font-size-micro);
 | 
				
			||||||
 | 
					    line-height: 1.8;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  i {
 | 
				
			||||||
 | 
					    line-height: 1.4;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.activity-wrap {
 | 
				
			||||||
 | 
					  .message-text--metadata {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .time {
 | 
				
			||||||
 | 
					      color: var(--s-300);
 | 
				
			||||||
 | 
					      font-size: var(--font-size-micro);
 | 
				
			||||||
 | 
					      margin-left: var(--space-small);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.is-image {
 | 
				
			||||||
 | 
					  .message-text--metadata {
 | 
				
			||||||
 | 
					    .time {
 | 
				
			||||||
 | 
					      bottom: var(--space-smaller);
 | 
				
			||||||
 | 
					      color: var(--white);
 | 
				
			||||||
 | 
					      position: absolute;
 | 
				
			||||||
 | 
					      right: var(--space-small);
 | 
				
			||||||
 | 
					      white-space: nowrap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.is-private {
 | 
				
			||||||
 | 
					  .message-text--metadata {
 | 
				
			||||||
 | 
					    align-items: flex-end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .time {
 | 
				
			||||||
 | 
					      color: var(--s-400);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.is-image {
 | 
				
			||||||
 | 
					    .time {
 | 
				
			||||||
 | 
					      position: inherit;
 | 
				
			||||||
 | 
					      padding-left: var(--space-one);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -1,41 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
  <div class="audio message-text__wrap">
 | 
					 | 
				
			||||||
    <a-player
 | 
					 | 
				
			||||||
      :music="playerOptions"
 | 
					 | 
				
			||||||
      mode="order"
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
    <span class="time">{{readableTime}}</span>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
import APlayer from 'vue-aplayer';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  components: {
 | 
					 | 
				
			||||||
    APlayer,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  props: [
 | 
					 | 
				
			||||||
    'url',
 | 
					 | 
				
			||||||
    'readableTime',
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  data() {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      musicObj: {
 | 
					 | 
				
			||||||
        title: ' ',
 | 
					 | 
				
			||||||
        author: ' ',
 | 
					 | 
				
			||||||
        autoplay: false,
 | 
					 | 
				
			||||||
        narrow: true,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    playerOptions() {
 | 
					 | 
				
			||||||
      return {
 | 
					 | 
				
			||||||
        ...this.musicObj,
 | 
					 | 
				
			||||||
        url: this.url,
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
@@ -16,13 +16,17 @@
 | 
				
			|||||||
        {{ $t('CONVERSATION.DOWNLOAD') }}
 | 
					        {{ $t('CONVERSATION.DOWNLOAD') }}
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <span class="time">{{ readableTime }}</span>
 | 
					 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  props: ['url', 'readableTime'],
 | 
					  props: {
 | 
				
			||||||
 | 
					    url: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      required: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    fileName() {
 | 
					    fileName() {
 | 
				
			||||||
      const filename = this.url.substring(this.url.lastIndexOf('/') + 1);
 | 
					      const filename = this.url.substring(this.url.lastIndexOf('/') + 1);
 | 
				
			||||||
@@ -31,7 +35,7 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    openLink() {
 | 
					    openLink() {
 | 
				
			||||||
      const win = window.open(this.url, '_blank');
 | 
					      const win = window.open(this.url, '_blank', 'noopener');
 | 
				
			||||||
      win.focus();
 | 
					      win.focus();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,20 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="image message-text__wrap">
 | 
					  <div class="image message-text__wrap">
 | 
				
			||||||
    <img
 | 
					    <img :src="url" @click="onClick" />
 | 
				
			||||||
      :src="url"
 | 
					 | 
				
			||||||
      v-on:click="onClick"
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
    <span class="time">{{readableTime}}</span>
 | 
					 | 
				
			||||||
    <woot-modal :show.sync="show" :on-close="onClose">
 | 
					    <woot-modal :show.sync="show" :on-close="onClose">
 | 
				
			||||||
      <img
 | 
					      <img :src="url" class="modal-image" />
 | 
				
			||||||
        :src="url"
 | 
					 | 
				
			||||||
        class="modal-image"
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </woot-modal>
 | 
					    </woot-modal>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  props: [
 | 
					  props: {
 | 
				
			||||||
    'url',
 | 
					    url: {
 | 
				
			||||||
    'readableTime',
 | 
					      type: String,
 | 
				
			||||||
  ],
 | 
					      required: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      show: false,
 | 
					      show: false,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
  <div class="map message-text__wrap">
 | 
					 | 
				
			||||||
    <img
 | 
					 | 
				
			||||||
      :src="locUrl"
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
    <span class="locname">{{label || ' '}}</span>
 | 
					 | 
				
			||||||
    <span class="time">{{readableTime}}</span>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  props: [
 | 
					 | 
				
			||||||
    'lat',
 | 
					 | 
				
			||||||
    'lng',
 | 
					 | 
				
			||||||
    'label',
 | 
					 | 
				
			||||||
    'readableTime',
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  data() {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      accessToken: 'pk.eyJ1IjoiY2hhdHdvb3QiLCJhIjoiY2oyazVsM3d0MDBmYjJxbmkyYXlwY3hzZyJ9.uWUdfItb0sSZQ4nfwlmuPg',
 | 
					 | 
				
			||||||
      zoomLevel: 14,
 | 
					 | 
				
			||||||
      mapType: 'mapbox.streets',
 | 
					 | 
				
			||||||
      apiEndPoint: 'https://api.mapbox.com/v4/',
 | 
					 | 
				
			||||||
      h: 100,
 | 
					 | 
				
			||||||
      w: 150,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    locUrl() {
 | 
					 | 
				
			||||||
      const { apiEndPoint, mapType, lat, lng, zoomLevel, h, w, accessToken } = this;
 | 
					 | 
				
			||||||
      return `${apiEndPoint}${mapType}/${lng},${lat},${zoomLevel}/${w}x${h}.png?access_token=${accessToken}`;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
@@ -1,12 +1,24 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <span class="message-text__wrap">
 | 
					  <span class="message-text__wrap">
 | 
				
			||||||
    <span v-html="message"></span>
 | 
					    <span v-html="message"></span>
 | 
				
			||||||
    <span class="time">{{ readableTime }}</span>
 | 
					 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  props: ['message', 'readableTime'],
 | 
					  props: {
 | 
				
			||||||
 | 
					    message: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: '',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    readableTime: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: '',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isEmail: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,6 +76,7 @@
 | 
				
			|||||||
        "ICON": "ion-link",
 | 
					        "ICON": "ion-link",
 | 
				
			||||||
        "CONTENT": "has shared a url"
 | 
					        "CONTENT": "has shared a url"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
 | 
					    "RECEIVED_VIA_EMAIL": "Received via email"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								app/javascript/shared/constants/contentType.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/javascript/shared/constants/contentType.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					export const CONTENT_TYPES = {
 | 
				
			||||||
 | 
					  INCOMING_EMAIL: 'incoming_email',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										9
									
								
								app/javascript/shared/mixins/contentTypeMixin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/javascript/shared/mixins/contentTypeMixin.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { CONTENT_TYPES } from '../constants/contentType';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    isEmailContentType() {
 | 
				
			||||||
 | 
					      return this.contentType === CONTENT_TYPES.INCOMING_EMAIL;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										32
									
								
								app/javascript/shared/mixins/specs/contentTypeMixin.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/javascript/shared/mixins/specs/contentTypeMixin.spec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					import { shallowMount } from '@vue/test-utils';
 | 
				
			||||||
 | 
					import contentTypeMixin from '../contentTypeMixin';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('contentTypeMixin', () => {
 | 
				
			||||||
 | 
					  it('returns true if contentType is incoming_email', () => {
 | 
				
			||||||
 | 
					    const Component = {
 | 
				
			||||||
 | 
					      render() {},
 | 
				
			||||||
 | 
					      mixins: [contentTypeMixin],
 | 
				
			||||||
 | 
					      computed: {
 | 
				
			||||||
 | 
					        contentType() {
 | 
				
			||||||
 | 
					          return 'incoming_email';
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const wrapper = shallowMount(Component);
 | 
				
			||||||
 | 
					    expect(wrapper.vm.isEmailContentType).toBe(true);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('returns false if contentType is not incoming_email', () => {
 | 
				
			||||||
 | 
					    const Component = {
 | 
				
			||||||
 | 
					      render() {},
 | 
				
			||||||
 | 
					      mixins: [contentTypeMixin],
 | 
				
			||||||
 | 
					      computed: {
 | 
				
			||||||
 | 
					        contentType() {
 | 
				
			||||||
 | 
					          return 'input_select';
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const wrapper = shallowMount(Component);
 | 
				
			||||||
 | 
					    expect(wrapper.vm.isEmailContentType).toBe(false);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -13,6 +13,7 @@ json.payload do
 | 
				
			|||||||
    json.inbox_id message.inbox_id
 | 
					    json.inbox_id message.inbox_id
 | 
				
			||||||
    json.conversation_id message.conversation.display_id
 | 
					    json.conversation_id message.conversation.display_id
 | 
				
			||||||
    json.message_type message.message_type_before_type_cast
 | 
					    json.message_type message.message_type_before_type_cast
 | 
				
			||||||
 | 
					    json.content_type message.content_type
 | 
				
			||||||
    json.created_at message.created_at.to_i
 | 
					    json.created_at message.created_at.to_i
 | 
				
			||||||
    json.private message.private
 | 
					    json.private message.private
 | 
				
			||||||
    json.source_id message.source_id
 | 
					    json.source_id message.source_id
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,6 @@
 | 
				
			|||||||
    "url-loader": "^2.0.0",
 | 
					    "url-loader": "^2.0.0",
 | 
				
			||||||
    "v-tooltip": "~2.0.2",
 | 
					    "v-tooltip": "~2.0.2",
 | 
				
			||||||
    "vue": "^2.6.0",
 | 
					    "vue": "^2.6.0",
 | 
				
			||||||
    "vue-aplayer": "~0.1.1",
 | 
					 | 
				
			||||||
    "vue-audio": "~0.0.7",
 | 
					    "vue-audio": "~0.0.7",
 | 
				
			||||||
    "vue-axios": "~1.2.2",
 | 
					    "vue-axios": "~1.2.2",
 | 
				
			||||||
    "vue-chartjs": "^3.4.2",
 | 
					    "vue-chartjs": "^3.4.2",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -1585,15 +1585,6 @@ anymatch@^3.0.3:
 | 
				
			|||||||
    normalize-path "^3.0.0"
 | 
					    normalize-path "^3.0.0"
 | 
				
			||||||
    picomatch "^2.0.4"
 | 
					    picomatch "^2.0.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
aplayer@^1.5.8:
 | 
					 | 
				
			||||||
  version "1.10.1"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/aplayer/-/aplayer-1.10.1.tgz#318289206107452cc39e8f552fa6cc6cb459a90c"
 | 
					 | 
				
			||||||
  integrity sha512-HAfyxgCUTLAqtYlxzzK9Fyqg6y+kZ9CqT1WfeWE8FSzwspT6oBqWOZHANPHF3RGTtC33IsyEgrfthPDzU5r9kQ==
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    balloon-css "^0.5.0"
 | 
					 | 
				
			||||||
    promise-polyfill "7.1.0"
 | 
					 | 
				
			||||||
    smoothscroll "0.4.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
aproba@^1.0.3, aproba@^1.1.1:
 | 
					aproba@^1.0.3, aproba@^1.1.1:
 | 
				
			||||||
  version "1.2.0"
 | 
					  version "1.2.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
 | 
					  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
 | 
				
			||||||
@@ -2021,11 +2012,6 @@ balanced-match@^1.0.0:
 | 
				
			|||||||
  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
 | 
					  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
 | 
				
			||||||
  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 | 
					  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
balloon-css@^0.5.0:
 | 
					 | 
				
			||||||
  version "0.5.2"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/balloon-css/-/balloon-css-0.5.2.tgz#9e2163565a136c9d4aa20e8400772ce3b738d3ff"
 | 
					 | 
				
			||||||
  integrity sha512-zheJpzwyNrG4t39vusA67v3BYg1HTVXOF8cErPEHzWK88PEOFwgo6Ea9VHOgOWNMgeuOtFVtB73NE2NWl9uDyQ==
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
base64-js@^1.0.2:
 | 
					base64-js@^1.0.2:
 | 
				
			||||||
  version "1.3.1"
 | 
					  version "1.3.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
 | 
					  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
 | 
				
			||||||
@@ -8539,11 +8525,6 @@ promise-inflight@^1.0.1:
 | 
				
			|||||||
  resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
 | 
					  resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
 | 
				
			||||||
  integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
 | 
					  integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
promise-polyfill@7.1.0:
 | 
					 | 
				
			||||||
  version "7.1.0"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-7.1.0.tgz#4d749485b44577c14137591c6f36e5d7e2dd3378"
 | 
					 | 
				
			||||||
  integrity sha512-P6NJ2wU/8fac44ENORsuqT8TiolKGB2u0fEClPtXezn7w5cmLIjM/7mhPlTebke2EPr6tmqZbXvnX0TxwykGrg==
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
prompts@^2.0.1:
 | 
					prompts@^2.0.1:
 | 
				
			||||||
  version "2.3.1"
 | 
					  version "2.3.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.1.tgz#b63a9ce2809f106fa9ae1277c275b167af46ea05"
 | 
					  resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.1.tgz#b63a9ce2809f106fa9ae1277c275b167af46ea05"
 | 
				
			||||||
@@ -9442,11 +9423,6 @@ slice-ansi@^2.1.0:
 | 
				
			|||||||
    astral-regex "^1.0.0"
 | 
					    astral-regex "^1.0.0"
 | 
				
			||||||
    is-fullwidth-code-point "^2.0.0"
 | 
					    is-fullwidth-code-point "^2.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
smoothscroll@0.4.0:
 | 
					 | 
				
			||||||
  version "0.4.0"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/smoothscroll/-/smoothscroll-0.4.0.tgz#40e507b46461408ba1b787d0081e1e883c4124a5"
 | 
					 | 
				
			||||||
  integrity sha512-sggQ3U2Un38b3+q/j1P4Y4fCboCtoUIaBYoge+Lb6Xg1H8RTIif/hugVr+ErMtIDpvBbhQfTjtiTeYAfbw1ZGQ==
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snapdragon-node@^2.0.1:
 | 
					snapdragon-node@^2.0.1:
 | 
				
			||||||
  version "2.1.1"
 | 
					  version "2.1.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
 | 
					  resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
 | 
				
			||||||
@@ -10524,13 +10500,6 @@ vm-browserify@^1.0.1:
 | 
				
			|||||||
  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
 | 
					  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
 | 
				
			||||||
  integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
 | 
					  integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vue-aplayer@~0.1.1:
 | 
					 | 
				
			||||||
  version "0.1.1"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/vue-aplayer/-/vue-aplayer-0.1.1.tgz#c5b486c664ac2818618ccf29a6dd1e4e2856dcdc"
 | 
					 | 
				
			||||||
  integrity sha1-xbSGxmSsKBhhjM8ppt0eTihW3Nw=
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    aplayer "^1.5.8"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vue-audio@~0.0.7:
 | 
					vue-audio@~0.0.7:
 | 
				
			||||||
  version "0.0.12"
 | 
					  version "0.0.12"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/vue-audio/-/vue-audio-0.0.12.tgz#0e4d7af19bc2cc8924a90a57e01edd7de0945cc4"
 | 
					  resolved "https://registry.yarnpkg.com/vue-audio/-/vue-audio-0.0.12.tgz#0e4d7af19bc2cc8924a90a57e01edd7de0945cc4"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user