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

Freegle / Iznik / 11495

09 May 2026 07:35AM UTC coverage: 69.06% (-3.8%) from 72.847%
11495

Pull #408

circleci

edwh
docs(migration): mark restartproject and repaircafewales as migrated (PR #408)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pull Request #408: feat(batch): migrate check_cgas, visualise, tn_sync + dry-run improvements

9127 of 10554 branches covered (86.48%)

Branch coverage included in aggregate %.

507 of 663 new or added lines in 16 files covered. (76.47%)

11902 existing lines in 138 files now uncovered.

101630 of 149824 relevant lines covered (67.83%)

19.56 hits per line

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

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

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

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

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

206
const props = defineProps({
1✔
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
1✔
233
const showRenege = ref(false)
1✔
234
const showOutcome = ref(false)
1✔
235
const outcomeType = ref(null)
1✔
236
const showPromise = ref(false)
1✔
237

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

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

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

261
if (refmsgid.value) {
1✔
262
  useMessageStore().fetch(refmsgid.value)
1✔
263
}
1✔
264

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

270
const takenBy = computed(() => {
1✔
271
  let ret = null
13✔
272

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

279
  return ret
13✔
280
})
13✔
281

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

288
function changeTime() {
1✔
289
  showPromise.value = true
1✔
290
}
1✔
291

292
function fetchMessages() {
1✔
293
  chatStore.fetchMessages(chatmessage.value.chatid)
1✔
294
}
1✔
295

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

299
  showOutcome.value = true
1✔
300
  outcomeType.value = type
1✔
301
}
1✔
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 TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc