• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Freegle / iznik-nuxt3 / c048d5d9-f95f-4246-9591-5caf910754e3

02 Sep 2025 03:31PM UTC coverage: 45.697% (+4.6%) from 41.088%
c048d5d9-f95f-4246-9591-5caf910754e3

push

circleci

edwh
WIP FreegleDocker CircleCI

1766 of 4622 branches covered (38.21%)

Branch coverage included in aggregate %.

4032 of 8066 relevant lines covered (49.99%)

112.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/components/MessageExpanded.vue
1
<template>
2
  <div v-if="message" :id="'msg-' + id" class="position-relative">
3
    <MessageAttachments
4
      v-if="gotAttachments"
5
      :id="id"
6
      :attachments="message?.attachments"
7
      class="image-wrapper"
8
      :disabled="message?.successful"
9
      show-zoom
10
      @zoom="$emit('zoom')"
11
    />
12
    <div class="d-flex mb-1 mt-2 justify-content-between p-2 p-md-0">
13
      <div class="d-flex flex-column justify-content-between w-100">
14
        <div v-if="!gotAttachments" class="d-flex">
15
          <MessageTag :id="id" def inline class="pl-2 pr-2" />
16
        </div>
17
        <MessageItemLocation
18
          :id="id"
19
          :matchedon="message.matchedon"
20
          class="mb-1 header-title flex-grow-1"
21
          :expanded="true"
22
        />
23
        <MessageActions v-if="actions" :id="id" />
24
      </div>
25
      <MessageHistoryExpanded :id="id" class="mb-1 d-none d-md-block" />
26
    </div>
27
    <div class="bg-white mb-3 p-2 p-md-0">
28
      <MessagePromised
29
        v-if="message.promised && replyable"
30
        :id="message.id"
31
        :to-me="message.promisedtome"
32
        class="mb-3 mt-1"
33
      />
34
      <MessageTextBody :id="id" />
35
      <MessageReplyInfo :message="message" />
36
      <div v-if="validPosition" class="mt-2 d-flex">
37
        <client-only>
38
          <MessageMap
39
            v-if="showMap && adRendered"
40
            :home="home"
41
            :position="{ lat: message.lat, lng: message.lng }"
42
            class="messagemap flex-grow-1"
43
            :height="breakpoint === 'xs' || breakpoint === 'sm' ? 150 : 250"
44
          />
45
        </client-only>
46
      </div>
47
      <MessageHistoryExpanded :id="id" class="d-block d-md-none mt-2 mt-md-0" />
48
      <VisibleWhen v-if="showAd && adId && !noAd" :at="['xs', 'sm']">
49
        <div class="d-flex justify-content-around mt-2">
50
          <ExternalDa
51
            :ad-unit-path="adUnitPath"
52
            :ad-id="adId"
53
            max-height="250px"
54
            :div-id="adId"
55
            :in-modal="inModal"
56
            show-logged-out
57
            @rendered="rendered"
58
          />
59
        </div>
60
      </VisibleWhen>
61
      <client-only>
62
        <MessageReplySection
63
          v-if="replyable && !replied"
64
          :id="id"
65
          class="mt-3"
66
          @close="$emit('close')"
67
          @sent="sent"
68
        />
69
      </client-only>
70
      <b-alert
71
        v-if="replied"
72
        variant="info"
73
        :model-value="true"
74
        class="mt-2"
75
        fade
76
      >
77
        We've sent your message. You'll get replies in the
78
        <nuxt-link no-prefetch to="/chats">Chats</nuxt-link> section on here,
79
        and by email.
80
      </b-alert>
81
    </div>
82
  </div>
83
</template>
84
<script setup>
85
import { ref, computed, watch, defineAsyncComponent } from 'vue'
86
import MessageReplyInfo from './MessageReplyInfo'
87
import { useMessageStore } from '~/stores/message'
88
import { useMiscStore } from '~/stores/misc'
89
import MessagePromised from '~/components/MessagePromised'
90
import MessageActions from '~/components/MessageActions'
91
import MessageTextBody from '~/components/MessageTextBody'
92
import MessageTag from '~/components/MessageTag'
93
import MessageItemLocation from '~/components/MessageItemLocation'
94
import MessageAttachments from '~/components/MessageAttachments'
95
import { useMe } from '~/composables/useMe'
96

97
const MessageHistoryExpanded = defineAsyncComponent(() =>
×
98
  import('~/components/MessageHistoryExpanded')
99
)
100

101
const props = defineProps({
×
102
  id: {
103
    type: Number,
104
    required: true,
105
  },
106
  showMap: {
107
    type: Boolean,
108
    required: false,
109
    default: true,
110
  },
111
  showAd: {
112
    type: Boolean,
113
    required: false,
114
    default: true,
115
  },
116
  hideClose: {
117
    type: Boolean,
118
    required: false,
119
    default: false,
120
  },
121
  replyable: {
122
    type: Boolean,
123
    required: false,
124
    default: true,
125
  },
126
  actions: {
127
    type: Boolean,
128
    required: false,
129
    default: true,
130
  },
131
  adUnitPath: {
132
    type: String,
133
    required: false,
134
    default: null,
135
  },
136
  adId: {
137
    type: String,
138
    required: false,
139
    default: null,
140
  },
141
  inModal: {
142
    type: Boolean,
143
    default: false,
144
  },
145
})
146

147
const emit = defineEmits(['zoom', 'close'])
×
148

149
const messageStore = useMessageStore()
×
150
const miscStore = useMiscStore()
×
151
const { me } = useMe()
×
152

153
// Data
154
const replied = ref(false)
×
155
const adRendered = ref(false)
×
156
const noAd = ref(false)
×
157

×
158
// Computed
159
const breakpoint = computed(() => {
160
  return miscStore.breakpoint
×
161
})
162

163
const message = computed(() => {
×
164
  return messageStore?.byId(props.id)
×
165
})
166

167
const gotAttachments = computed(() => {
×
168
  return (
×
169
    message.value &&
×
170
    message.value.attachments &&
×
171
    message.value.attachments?.length
172
  )
173
})
174

175
const validPosition = computed(() => {
×
176
  return message.value.lat || message.value.lng
×
177
})
178

179
const home = computed(() => {
×
180
  let ret = null
×
181

182
  if (me.value?.lat || me.value?.lng) {
×
183
    ret = {
×
184
      lat: me.value.lat,
185
      lng: me.value.lng,
186
    }
187
  }
188

189
  return ret
×
190
})
191

192
// Watch
193
watch(
×
194
  breakpoint,
195
  (newVal) => {
196
    // The ad is only shown on xs and sm, so for others we need to pretend it has been.
197
    if (newVal !== 'xs' && newVal !== 'sm') {
×
198
      adRendered.value = true
×
199
    }
200
  },
201
  { immediate: true }
202
)
203

×
204
// Methods
205
function sent() {
206
  emit('close')
×
207
  replied.value = true
×
208
}
209

210
function rendered(shown) {
×
211
  adRendered.value = true
×
212
  noAd.value = !shown
×
213
}
214
</script>
215
<style scoped lang="scss">
216
@import 'bootstrap/scss/functions';
217
@import 'bootstrap/scss/variables';
218
@import 'bootstrap/scss/mixins/_breakpoints';
219

220
.header--size4 {
221
  color: $colour-info-fg !important;
222
  font-weight: bold;
223
}
224

225
.image-wrapper {
226
  position: relative;
227
}
228
</style>
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc