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

Freegle / iznik-nuxt3 / 9bce52b0-957c-43ee-92e4-3867075656a0

04 Dec 2025 02:52PM UTC coverage: 42.676% (-1.8%) from 44.461%
9bce52b0-957c-43ee-92e4-3867075656a0

push

circleci

edwh
Modernize chat buttons, fix sidebars and footer layout

- ChatFooter: Modernize desktop action buttons to chip-style design
- MessageExpanded: Force ratings to hide on mobile with !important
- MyMessageReply: Hide ratings section on xxs screens (≤320px)
- SidebarRight: Full width and height for job ads, match left sidebar
- SidebarLeft: Remove margin from footer wrapper
- BotLeftBox: Rework footer with text links left, social icons right

2986 of 7770 branches covered (38.43%)

Branch coverage included in aggregate %.

3459 of 7332 relevant lines covered (47.18%)

13.59 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="otheruser.profile.paththumb"
15
            :name="otheruser.displayname"
16
            class="mr-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" class="promised-text mt-2">
41
          <span
42
            v-if="
43
              chatmessage.secondsago < 60 || chatmessage.id > chat.lastmsgseen
44
            "
45
            class="prewrap font-weight-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="mr-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="mr-2 mb-1"
88
            />
89
            <b-button
90
              v-if="refmsg.promisecount && refmsg.availablenow"
91
              variant="secondary"
92
              size="sm"
93
              class="mr-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="mr-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="mr-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" class="promised-text mt-2">
144
          <span
145
            v-if="
146
              chatmessage.secondsago < 60 || chatmessage.id > chat.lastmsgseen
×
147
            "
148
            class="prewrap font-weight-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
  refmsgid,
253
  refmsg,
254
  me,
×
255
  myid,
256
  otheruser,
257
  fetchMessage,
258
} = useChatMessageBase(props.chatid, props.id, props.pov)
×
259

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

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

269
const takenBy = computed(() => {
270
  let ret = null
271

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

278
  return ret
279
})
280

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

287
function changeTime() {
288
  showPromise.value = true
289
}
290

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

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

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

307
.chat-message-promised {
308
  max-width: 100%;
309
}
310

311
.promised-message {
312
  width: 100%;
313
}
314

315
.promised-message--mine {
316
  margin-left: auto;
317
}
318

319
.promised-wrapper {
×
320
  background-color: #ffffff;
×
321
  border: 1px solid rgba(0, 0, 0, 0.1);
322
  border-radius: 10px;
323
  padding: 12px;
324
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
×
325
}
×
326

327
.promised-header {
328
  display: flex;
×
329
  align-items: center;
×
330
  margin-bottom: 8px;
331
}
×
332

×
333
.promised-label {
×
334
  font-size: 0.85rem;
×
335
  color: #333;
336
}
337

×
338
.promised-actions {
339
  display: flex;
340
  flex-wrap: wrap;
341
  gap: 4px;
×
342
}
×
343

×
344
.promised-text {
345
  font-size: 0.9rem;
346
  padding: 8px;
×
347
  background: $color-gray--lighter;
×
348
  border-radius: 8px;
349
}
350
</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