Files
apollo/packages/test-e2e/src/components/ChannelView.vue
T
Guillaume Chau 446333e616 chore: upgrade deps
Vue CLI 5
Cypress 10
2022-06-23 14:25:38 +02:00

164 lines
3.4 KiB
Vue

<script>
import MessageItem from './MessageItem.vue'
import MessageForm from './MessageForm.vue'
export default {
name: 'ChannelView',
components: {
MessageItem,
MessageForm,
},
props: {
id: {
type: String,
required: true,
},
},
watch: {
id: {
handler () {
this.$_init = false
},
immediate: true,
},
},
methods: {
onMessageChanged (previousResult, { subscriptionData }) {
const { type, message } = subscriptionData.data.messageChanged
// No list change
if (type === 'updated') return previousResult
const messages = previousResult.channel.messages.slice()
// Add or remove item
if (type === 'added') {
messages.push(message)
} else if (type === 'removed') {
const index = messages.findIndex(m => m.id === message.id)
if (index !== -1) messages.splice(index, 1)
}
// New query result
return {
channel: {
...previousResult.channel,
messages,
},
}
},
async scrollToBottom (force = false) {
const el = this.$refs.body
// No body element yet
if (!el) {
setTimeout(() => this.scrollToBottom(force), 100)
return
}
// User is scrolling up => no auto scroll
if (!force && el.scrollTop + el.clientHeight < el.scrollHeight - 100) return
// Scroll to bottom
await this.$nextTick()
el.scrollTop = el.scrollHeight
},
onResult (result) {
// The first time we load a channel, we force scroll to bottom
this.scrollToBottom(!this.$_init)
this.$_init = true
},
},
}
</script>
<template>
<div class="channel-view">
<ApolloQuery
:query="require('../graphql/channel.gql')"
:variables="{
id
}"
@result="onResult"
>
<template #default="{ result: { data, loading } }">
<div
v-if="!data && loading"
class="loading"
>
Loading...
</div>
<div v-else-if="data?.channel">
<!-- Websockets -->
<ApolloSubscribeToMore
:document="require('../graphql/messageChanged.gql')"
:variables="{
channelId: id,
}"
:update-query="onMessageChanged"
/>
<div class="wrapper">
<div class="header">
<div class="id">
#{{ data.channel.id }}
</div>
<div class="name">
{{ data.channel.name }}
</div>
</div>
<div
ref="body"
class="body"
>
<MessageItem
v-for="message in data.channel.messages"
:key="message.id"
:message="message"
/>
</div>
<div class="footer">
<MessageForm :channel-id="id" />
</div>
</div>
</div>
</template>
</ApolloQuery>
</div>
</template>
<style lang="stylus" scoped>
@import '~@/style/imports'
.wrapper
height 100vh
display grid
grid-template-columns 1fr
grid-template-rows auto 1fr auto
.header
padding 12px
border-bottom $border
.id
font-family monospace
margin-bottom 4px
.name
color #555
.body
overflow-x hidden
overflow-y auto
.footer
border-top $border
</style>