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

Freegle / iznik-nuxt3 / c1db7197-804e-45b4-8d43-ff5992ab766b

30 Mar 2026 09:10PM UTC coverage: 44.828% (+1.4%) from 43.397%
c1db7197-804e-45b4-8d43-ff5992ab766b

push

circleci

CircleCI Auto-merge
Auto-merge master to production after successful tests - Original commit: fix: saveEmail takes raw string, not object

4385 of 10026 branches covered (43.74%)

Branch coverage included in aggregate %.

0 of 2 new or added lines in 2 files covered. (0.0%)

454 existing lines in 28 files now uncovered.

1981 of 4175 relevant lines covered (47.45%)

59.5 hits per line

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

0.0
/components/ChatMessagePromised.vue
1
<template>
2
  <div class="chat-message-promised">
×
3
    <!-- Received promise (from other user) -->
4
    <div v-if="chatmessage?.userid != myid" class="promised-message">
5
      <div v-if="!refmsg" class="text-muted small">
×
6
        This chat message refers to a post (<v-icon
7
          icon="hashtag"
8
          class="text-muted fa-0-8x"
9
        />{{ chatmessage.refmsgid }}) which has been deleted.
10
      </div>
11
      <div v-else class="promised-wrapper">
12
        <div class="promised-header">
13
          <ProfileImage
14
            :image="chat?.icon"
×
15
            :name="otheruser?.displayname"
×
16
            class="me-2 inline"
17
            is-thumbnail
18
            size="sm"
19
          />
20
          <span class="promised-label"
×
21
            >Good news! You've been promised this:</span
22
          >
23
        </div>
24
        <ChatMessageCard :id="refmsgid" />
×
25
        <AddToCalendar
26
          v-if="tryst?.calendarLink"
27
          :calendar-link="tryst.calendarLink"
28
          class="mt-2"
×
29
        />
30
        <notice-message
31
          v-if="refmsg.outcomes?.length || refmsg.deleted"
32
          class="mt-2"
33
        >
34
          <v-icon icon="info-circle" />
35
          <span v-if="refmsg.type === 'Offer'">
×
36
            This is no longer available.
37
          </span>
38
          <span v-else> They are no longer looking for this. </span>
39
        </notice-message>
40
        <div v-if="emessage && !isEmptyMessage" class="promised-text mt-2">
×
41
          <span
42
            v-if="
×
43
              chatmessage.secondsago < 60 || chatmessage.id > chat.lastmsgseen
44
            "
45
            class="prewrap fw-bold"
46
            >{{ emessage }}</span
47
          >
48
          <span v-else class="preline forcebreak">{{ emessage }}</span>
49
        </div>
50
      </div>
51
    </div>
52

53
    <!-- Sent promise (from current user) -->
54
    <div v-else class="promised-message promised-message--mine">
55
      <div v-if="!refmsg" class="text-muted small">
×
56
        This chat message refers to a post (<v-icon
57
          icon="hashtag"
58
          class="text-muted fa-0-8x"
59
        />{{ chatmessage.refmsgid }}) which has been deleted.
60
      </div>
61
      <div v-else class="promised-wrapper">
62
        <div class="promised-header">
63
          <ProfileImage
64
            :image="me?.profile?.path"
×
65
            :name="me?.displayname"
×
66
            class="me-2 inline"
67
            is-thumbnail
68
            size="sm"
69
          />
70
          <span class="promised-label">
71
            You promised <strong>{{ otheruser?.displayname }}</strong
×
72
            >:
73
          </span>
74
        </div>
75
        <ChatMessageCard :id="refmsgid" :show-location="false" />
×
76
        <p v-if="tryst?.arrangedfor" class="small text-info mt-2 mb-1">
77
          Handover arranged for
78
          <strong
79
            ><DateFormatted :value="tryst.arrangedfor" format="weekdaytime"
80
          /></strong>
81
        </p>
82
        <div v-if="refmsg" class="promised-actions mt-2">
×
83
          <template v-if="tryst">
×
84
            <AddToCalendar
85
              v-if="tryst?.calendarLink"
86
              :calendar-link="tryst.calendarLink"
87
              class="me-2 mb-1"
88
            />
89
            <b-button
90
              v-if="refmsg.promisecount && refmsg.availablenow"
×
91
              variant="secondary"
92
              size="sm"
93
              class="me-2 mb-1"
94
              @click="changeTime"
95
            >
96
              <v-icon icon="pen" />
×
97
              Change time
98
            </b-button>
99
          </template>
100
          <template v-else-if="refmsg.promisecount && refmsg.availablenow">
×
101
            <b-button
102
              variant="secondary"
103
              size="sm"
104
              class="me-2 mb-1"
105
              @click="changeTime"
106
            >
107
              <v-icon icon="pen" />
×
108
              Set time
109
            </b-button>
110
          </template>
111
          <b-button
112
            v-if="refmsg.promisecount && refmsg.availablenow"
×
113
            variant="warning"
114
            size="sm"
115
            class="me-2 mb-1"
116
            @click="unpromise"
117
          >
118
            Unpromise
119
          </b-button>
×
120
          <b-button
121
            v-if="refmsg.availablenow"
×
122
            variant="primary"
123
            size="sm"
124
            class="mb-1"
125
            @click="outcome('Taken')"
×
126
          >
127
            Mark as TAKEN
128
          </b-button>
×
129
        </div>
130
        <notice-message
131
          v-if="refmsg.outcomes?.length || refmsg.deleted"
132
          class="mt-2"
133
        >
134
          <v-icon icon="info-circle" />
135
          <span v-if="refmsg.type === 'Offer'">
×
136
            This is no longer available.
137
          </span>
138
          <span v-else> They are no longer looking for this. </span>
×
139
        </notice-message>
140
        <p v-else-if="!refmsg?.availablenow" class="text-muted small mt-2">
141
          This has now been taken.
142
        </p>
143
        <div v-if="emessage && !isEmptyMessage" class="promised-text mt-2">
×
144
          <span
145
            v-if="
×
146
              chatmessage.secondsago < 60 || chatmessage.id > chat.lastmsgseen
147
            "
148
            class="prewrap fw-bold"
149
            >{{ emessage }}</span
150
          >
151
          <span v-else class="preline forcebreak">{{ emessage }}</span>
152
        </div>
153
        <PromiseModal
154
          v-if="showPromise"
×
155
          :messages="[refmsg]"
156
          :selected-message="refmsgid"
157
          :users="otheruser ? [otheruser] : []"
×
158
          :selected-user="otheruser ? otheruser.id : null"
×
159
          @hidden="showPromise = false"
×
160
        />
161
      </div>
162
    </div>
163
    <RenegeModal
164
      v-if="showRenege && refmsgid"
×
165
      :messages="[refmsgid]"
166
      :selected-message="refmsgid"
167
      :users="[otheruser]"
168
      :selected-user="otheruser.id"
169
      @hide="fetchMessages"
170
      @hidden="showRenege = false"
×
171
    />
172
    <OutcomeModal
173
      v-if="showOutcome && refmsgid"
×
174
      :id="refmsgid"
175
      :taken-by="takenBy"
176
      :type="outcomeType"
177
      @outcome="fetchMessage"
178
      @hidden="showOutcome = false"
×
179
    />
180
  </div>
181
</template>
182
<script setup>
183
import { ref, defineAsyncComponent } from 'vue'
184
import DateFormatted from './DateFormatted'
185
import { useTrystStore } from '~/stores/tryst'
186
import { fetchOurOffers } from '~/composables/useThrottle'
187
import { useChatStore } from '~/stores/chat'
188
import {
189
  fetchReferencedMessage,
190
  useChatMessageBase,
191
} from '~/composables/useChat'
192
import { useMessageStore } from '~/stores/message'
193
import AddToCalendar from '~/components/AddToCalendar'
194
import ProfileImage from '~/components/ProfileImage'
195
import ChatMessageCard from '~/components/ChatMessageCard'
196

197
const OutcomeModal = defineAsyncComponent(() =>
×
198
  import('~/components/OutcomeModal')
199
)
200

201
const RenegeModal = defineAsyncComponent(() => import('./RenegeModal'))
202
const PromiseModal = defineAsyncComponent(() =>
203
  import('~/components/PromiseModal')
204
)
205

206
const props = defineProps({
207
  chatid: {
208
    type: Number,
209
    required: true,
210
  },
211
  id: {
212
    type: Number,
213
    required: true,
214
  },
215
  last: {
216
    type: Boolean,
217
    required: false,
218
    default: false,
219
  },
220
  pov: {
221
    type: Number,
222
    required: false,
223
    default: null,
224
  },
225
  highlightEmails: {
226
    type: Boolean,
227
    required: false,
228
    default: false,
229
  },
230
})
231

232
// Data properties
233
const showRenege = ref(false)
234
const showOutcome = ref(false)
235
const outcomeType = ref(null)
236
const showPromise = ref(false)
237

238
// Stores
239
const trystStore = useTrystStore()
240
const chatStore = useChatStore()
241
const messageStore = useMessageStore()
242

243
// Setup
244
await trystStore.fetch()
×
245
await fetchReferencedMessage(props.chatid, props.id)
246

247
// Use the chat base composable
248
const {
×
249
  chat,
250
  chatmessage,
251
  emessage,
252
  isEmptyMessage,
253
  refmsgid,
254
  refmsg,
255
  me,
256
  myid,
257
  otheruser,
258
  fetchMessage,
259
} = useChatMessageBase(props.chatid, props.id, props.pov)
260

UNCOV
261
if (refmsgid.value) {
×
262
  useMessageStore().fetch(refmsgid.value)
263
}
264

265
// Component-specific computed properties
UNCOV
266
const tryst = computed(() => {
×
267
  return otheruser.value ? trystStore?.getByUser(otheruser.value.id) : null
×
268
})
269

270
const takenBy = computed(() => {
UNCOV
271
  let ret = null
×
272

UNCOV
273
  if (otheruser.value) {
×
274
    ret = otheruser.value
275
    ret.userid = otheruser.value.id
276
    ret.count = 1
277
  }
278

279
  return ret
280
})
281

282
// Methods
283
function unpromise() {
×
UNCOV
284
  showRenege.value = true
×
285
  fetchOurOffers()
286
}
287

288
function changeTime() {
×
UNCOV
289
  showPromise.value = true
×
290
}
291

292
function fetchMessages() {
×
UNCOV
293
  chatStore.fetchMessages(chatmessage.value.chatid)
×
294
}
295

296
async function outcome(type) {
×
UNCOV
297
  await messageStore.fetch(refmsgid.value)
×
298

299
  showOutcome.value = true
300
  outcomeType.value = type
301
}
302
</script>
303
<style scoped lang="scss">
304
@import 'bootstrap/scss/functions';
305
@import 'bootstrap/scss/variables';
306
@import 'bootstrap/scss/mixins/_breakpoints';
307
@import 'assets/css/_color-vars.scss';
308

309
.chat-message-promised {
310
  max-width: 100%;
311

312
  @include media-breakpoint-up(lg) {
313
    max-width: 400px;
314
  }
315
}
316

317
.promised-message {
318
  width: 100%;
319
}
320

321
.promised-message--mine {
322
  margin-left: auto;
323
}
324

325
.promised-wrapper {
326
  background-color: $color-white;
327
  border: 1px solid rgba(0, 0, 0, 0.1);
328
  border-radius: var(--radius-lg, 0.75rem);
329
  padding: 12px;
330
  box-shadow: var(--shadow-sm);
331
}
332

333
.promised-header {
334
  display: flex;
335
  align-items: center;
336
  margin-bottom: 8px;
337
}
338

339
.promised-label {
340
  font-size: 0.85rem;
341
  color: $color-gray--darker;
342
}
343

344
.promised-actions {
345
  display: flex;
346
  flex-wrap: wrap;
347
  gap: 4px;
348
}
349

350
.promised-text {
351
  font-size: 0.9rem;
352
  padding: 8px;
353
  background: $color-gray--lighter;
354
  border-radius: var(--radius-md, 0.5rem);
355
}
356
</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