mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge pull request #6579 from Ocelot-Social-Community/chat-pagniate-rooms
feat(webapp): chat paginate rooms
This commit is contained in:
commit
640e713f0a
@ -13,8 +13,8 @@ export const createRoomMutation = () => {
|
||||
|
||||
export const roomQuery = () => {
|
||||
return gql`
|
||||
query {
|
||||
Room {
|
||||
query Room($first: Int, $offset: Int, $id: ID) {
|
||||
Room(first: $first, offset: $offset, id: $id, orderBy: createdAt_desc) {
|
||||
id
|
||||
roomId
|
||||
roomName
|
||||
|
||||
@ -48,6 +48,14 @@ describe('Room', () => {
|
||||
id: 'not-chatting-user',
|
||||
name: 'Not Chatting User',
|
||||
}),
|
||||
Factory.build('user', {
|
||||
id: 'second-chatting-user',
|
||||
name: 'Second Chatting User',
|
||||
}),
|
||||
Factory.build('user', {
|
||||
id: 'third-chatting-user',
|
||||
name: 'Third Chatting User',
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
@ -260,4 +268,178 @@ describe('Room', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('query several rooms', () => {
|
||||
beforeAll(async () => {
|
||||
authenticatedUser = await chattingUser.toJson()
|
||||
await mutate({
|
||||
mutation: createRoomMutation(),
|
||||
variables: {
|
||||
userId: 'second-chatting-user',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: createRoomMutation(),
|
||||
variables: {
|
||||
userId: 'third-chatting-user',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('returns the rooms paginated', async () => {
|
||||
expect(await query({ query: roomQuery(), variables: { first: 2, offset: 0 } })).toMatchObject(
|
||||
{
|
||||
errors: undefined,
|
||||
data: {
|
||||
Room: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
roomId: expect.any(String),
|
||||
roomName: 'Third Chatting User',
|
||||
users: expect.arrayContaining([
|
||||
{
|
||||
_id: 'chatting-user',
|
||||
id: 'chatting-user',
|
||||
name: 'Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'third-chatting-user',
|
||||
id: 'third-chatting-user',
|
||||
name: 'Third Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
]),
|
||||
},
|
||||
{
|
||||
id: expect.any(String),
|
||||
roomId: expect.any(String),
|
||||
roomName: 'Second Chatting User',
|
||||
users: expect.arrayContaining([
|
||||
{
|
||||
_id: 'chatting-user',
|
||||
id: 'chatting-user',
|
||||
name: 'Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'second-chatting-user',
|
||||
id: 'second-chatting-user',
|
||||
name: 'Second Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
expect(await query({ query: roomQuery(), variables: { first: 2, offset: 2 } })).toMatchObject(
|
||||
{
|
||||
errors: undefined,
|
||||
data: {
|
||||
Room: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
roomId: expect.any(String),
|
||||
roomName: 'Other Chatting User',
|
||||
users: expect.arrayContaining([
|
||||
{
|
||||
_id: 'chatting-user',
|
||||
id: 'chatting-user',
|
||||
name: 'Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'other-chatting-user',
|
||||
id: 'other-chatting-user',
|
||||
name: 'Other Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('query single room', () => {
|
||||
let result: any = null
|
||||
beforeAll(async () => {
|
||||
authenticatedUser = await chattingUser.toJson()
|
||||
result = await query({ query: roomQuery() })
|
||||
})
|
||||
describe('as chatter of room', () => {
|
||||
it('returns the room', async () => {
|
||||
expect(
|
||||
await query({
|
||||
query: roomQuery(),
|
||||
variables: { first: 2, offset: 0, id: result.data.Room[0].id },
|
||||
}),
|
||||
).toMatchObject({
|
||||
errors: undefined,
|
||||
data: {
|
||||
Room: [
|
||||
{
|
||||
id: expect.any(String),
|
||||
roomId: expect.any(String),
|
||||
roomName: 'Third Chatting User',
|
||||
users: expect.arrayContaining([
|
||||
{
|
||||
_id: 'chatting-user',
|
||||
id: 'chatting-user',
|
||||
name: 'Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
{
|
||||
_id: 'third-chatting-user',
|
||||
id: 'third-chatting-user',
|
||||
name: 'Third Chatting User',
|
||||
avatar: {
|
||||
url: expect.any(String),
|
||||
},
|
||||
},
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
})
|
||||
describe('as not chatter of room', () => {
|
||||
beforeAll(async () => {
|
||||
authenticatedUser = await notChattingUser.toJson()
|
||||
})
|
||||
it('returns no room', async () => {
|
||||
authenticatedUser = await notChattingUser.toJson()
|
||||
expect(
|
||||
await query({
|
||||
query: roomQuery(),
|
||||
variables: { first: 2, offset: 0, id: result.data.Room[0].id },
|
||||
}),
|
||||
).toMatchObject({
|
||||
errors: undefined,
|
||||
data: {
|
||||
Room: [],
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -5,6 +5,11 @@
|
||||
# users_some: _UserFilter
|
||||
# }
|
||||
|
||||
# TODO change this to last message date
|
||||
enum _RoomOrdering {
|
||||
createdAt_desc
|
||||
}
|
||||
|
||||
type Room {
|
||||
id: ID!
|
||||
createdAt: String
|
||||
@ -24,5 +29,8 @@ type Mutation {
|
||||
}
|
||||
|
||||
type Query {
|
||||
Room: [Room]
|
||||
Room(
|
||||
id: ID
|
||||
orderBy: [_RoomOrdering]
|
||||
): [Room]
|
||||
}
|
||||
|
||||
@ -13,13 +13,15 @@
|
||||
:messages-loaded="messagesLoaded"
|
||||
:rooms="JSON.stringify(rooms)"
|
||||
:room-actions="JSON.stringify(roomActions)"
|
||||
:rooms-loaded="true"
|
||||
:rooms-loaded="roomsLoaded"
|
||||
:loading-rooms="loadingRooms"
|
||||
show-files="false"
|
||||
show-audio="false"
|
||||
:styles="JSON.stringify(computedChatStyle)"
|
||||
:show-footer="true"
|
||||
@send-message="sendMessage($event.detail[0])"
|
||||
@fetch-messages="fetchMessages($event.detail[0])"
|
||||
@fetch-more-rooms="fetchRooms"
|
||||
:responsive-breakpoint="responsiveBreakpoint"
|
||||
:single-room="singleRoom"
|
||||
show-reaction-emojis="false"
|
||||
@ -143,17 +145,20 @@ export default {
|
||||
{ name: 'deleteRoom', title: 'Delete Room' },
|
||||
*/
|
||||
],
|
||||
rooms: [],
|
||||
messages: [],
|
||||
messagesLoaded: true,
|
||||
|
||||
showDemoOptions: true,
|
||||
responsiveBreakpoint: 600,
|
||||
rooms: [],
|
||||
roomsLoaded: false,
|
||||
roomPage: 0,
|
||||
roomPageSize: 10, // TODO pagination is a problem with single rooms - cant use
|
||||
singleRoom: !!this.singleRoomId || false,
|
||||
selectedRoom: null,
|
||||
loadingRooms: true,
|
||||
messagesLoaded: false,
|
||||
messagePage: 0,
|
||||
messagePageSize: 20,
|
||||
roomPage: 0,
|
||||
roomPageSize: 999, // TODO pagination is a problem with single rooms - cant use
|
||||
selectedRoom: null,
|
||||
messages: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -165,8 +170,8 @@ export default {
|
||||
userId: this.singleRoomId,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.$apollo.queries.Rooms.refetch()
|
||||
.then(({ data: { CreateRoom } }) => {
|
||||
this.fetchRooms({ room: CreateRoom })
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(error)
|
||||
@ -174,6 +179,8 @@ export default {
|
||||
.finally(() => {
|
||||
// this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.fetchRooms()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -181,12 +188,49 @@ export default {
|
||||
currentUser: 'auth/user',
|
||||
}),
|
||||
computedChatStyle() {
|
||||
// TODO light/dark theme still needed?
|
||||
// return this.theme === 'light' ? chatStyle.STYLE.light : chatStyle.STYLE.dark
|
||||
return chatStyle.STYLE.light
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async fetchRooms({ room } = {}) {
|
||||
this.roomsLoaded = false
|
||||
const offset = this.roomPage * this.roomPageSize
|
||||
try {
|
||||
const {
|
||||
data: { Room },
|
||||
} = await this.$apollo.query({
|
||||
query: roomQuery(),
|
||||
variables: {
|
||||
id: room?.id,
|
||||
first: this.roomPageSize,
|
||||
offset,
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
})
|
||||
|
||||
const newRooms = Room.map((r) => {
|
||||
return {
|
||||
...r,
|
||||
users: r.users.map((u) => {
|
||||
return { ...u, username: u.name, avatar: u.avatar?.url }
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
this.rooms = [...this.rooms, ...newRooms]
|
||||
|
||||
if (Room.length < this.roomPageSize) {
|
||||
this.roomsLoaded = true
|
||||
}
|
||||
this.roomPage += 1
|
||||
} catch (error) {
|
||||
this.rooms = []
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
// must be set false after initial rooms are loaded and never changed again
|
||||
this.loadingRooms = false
|
||||
},
|
||||
|
||||
async fetchMessages({ room, options = {} }) {
|
||||
if (this.selectedRoom?.id !== room.id) {
|
||||
this.messages = []
|
||||
@ -224,13 +268,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
refetchMessage(roomId) {
|
||||
this.fetchMessages({
|
||||
room: this.rooms.find((r) => r.roomId === roomId),
|
||||
options: { refetch: true },
|
||||
})
|
||||
},
|
||||
|
||||
async sendMessage(message) {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
@ -243,7 +280,10 @@ export default {
|
||||
} catch (error) {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
this.refetchMessage(message.roomId)
|
||||
this.fetchMessages({
|
||||
room: this.rooms.find((r) => r.roomId === message.roomId),
|
||||
options: { refetch: true },
|
||||
})
|
||||
},
|
||||
|
||||
getInitialsName(fullname) {
|
||||
@ -251,45 +291,6 @@ export default {
|
||||
return fullname.match(/\b\w/g).join('').substring(0, 3).toUpperCase()
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
Rooms: {
|
||||
query() {
|
||||
return roomQuery()
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
first: this.roomPageSize,
|
||||
offset: this.roomPage * this.roomPageSize,
|
||||
}
|
||||
},
|
||||
update({ Room }) {
|
||||
if (!Room) {
|
||||
this.rooms = []
|
||||
return
|
||||
}
|
||||
|
||||
// Backend result needs mapping of the following values
|
||||
// room[i].users[j].name -> room[i].users[j].username
|
||||
// room[i].users[j].avatar.url -> room[i].users[j].avatar
|
||||
// also filter rooms for the single room
|
||||
this.rooms = Room.map((r) => {
|
||||
return {
|
||||
...r,
|
||||
users: r.users.map((u) => {
|
||||
return { ...u, username: u.name, avatar: u.avatar?.url }
|
||||
}),
|
||||
}
|
||||
}).filter((r) =>
|
||||
this.singleRoom ? r.users.filter((u) => u.id === this.singleRoomId).length > 0 : true,
|
||||
)
|
||||
},
|
||||
error(error) {
|
||||
this.rooms = []
|
||||
this.$toast.error(error.message)
|
||||
},
|
||||
fetchPolicy: 'no-cache',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const roomQuery = () => gql`
|
||||
query Room($first: Int, $offset: Int) {
|
||||
Room(first: $first, offset: $offset) {
|
||||
query Room($first: Int, $offset: Int, $id: ID) {
|
||||
Room(first: $first, offset: $offset, id: $id, orderBy: createdAt_desc) {
|
||||
id
|
||||
roomId
|
||||
roomName
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user