Skip to content

Commit b2d25cd

Browse files
authored
Merge pull request #13465 from nextcloud/fix/noid/polls-ts
2 parents b681d0e + bfdd93b commit b2d25cd

File tree

10 files changed

+135
-98
lines changed

10 files changed

+135
-98
lines changed

src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ import CallButton from '../../../../TopBar/CallButton.vue'
141141
import { useIsInCall } from '../../../../../composables/useIsInCall.js'
142142
import { useMessageInfo } from '../../../../../composables/useMessageInfo.js'
143143
import { EventBus } from '../../../../../services/EventBus.js'
144-
import { usePollsStore } from '../../../../../stores/polls.js'
144+
import { usePollsStore } from '../../../../../stores/polls.ts'
145145
import { parseSpecialSymbols, parseMentions } from '../../../../../utils/textParse.ts'
146146

147147
// Regular expression to check for Unicode emojis in message text

src/components/MessagesList/MessagesGroup/Message/MessagePart/Poll.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { t } from '@nextcloud/l10n'
3939
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
4040

4141
import { POLL } from '../../../../../constants.js'
42-
import { usePollsStore } from '../../../../../stores/polls.js'
42+
import { usePollsStore } from '../../../../../stores/polls.ts'
4343

4444
export default {
4545
name: 'Poll',

src/components/NewMessage/NewMessagePollEditor.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadi
7777
import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'
7878
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
7979

80-
import { usePollsStore } from '../../stores/polls.js'
80+
import { usePollsStore } from '../../stores/polls.ts'
8181

8282
export default {
8383
name: 'NewMessagePollEditor',

src/components/PollViewer/PollViewer.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ import { useId } from '../../composables/useId.ts'
108108
import { useIsInCall } from '../../composables/useIsInCall.js'
109109
import { POLL } from '../../constants.js'
110110
import { EventBus } from '../../services/EventBus.js'
111-
import { usePollsStore } from '../../stores/polls.js'
111+
import { usePollsStore } from '../../stores/polls.ts'
112112

113113
export default {
114114
name: 'PollViewer',

src/services/pollService.js

-65
This file was deleted.

src/services/pollService.ts

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import axios from '@nextcloud/axios'
7+
import { generateOcsUrl } from '@nextcloud/router'
8+
9+
import type {
10+
closePollResponse,
11+
createPollParams,
12+
createPollResponse,
13+
getPollResponse,
14+
votePollParams,
15+
votePollResponse,
16+
} from '../types/index.ts'
17+
18+
type createPollPayload = { token: string } & createPollParams
19+
20+
/**
21+
* @param payload The payload
22+
* @param payload.token The conversation token
23+
* @param payload.question The question of the poll
24+
* @param payload.options The options participants can vote for
25+
* @param payload.resultMode Result mode of the poll (0 - always visible | 1 - hidden until the poll is closed)
26+
* @param payload.maxVotes Maximum amount of options a user can vote for (0 - unlimited | 1 - single answer)
27+
*/
28+
const createPoll = async ({ token, question, options, resultMode, maxVotes }: createPollPayload): createPollResponse => {
29+
return axios.post(generateOcsUrl('apps/spreed/api/v1/poll/{token}', { token }), {
30+
question,
31+
options,
32+
resultMode,
33+
maxVotes,
34+
} as createPollParams)
35+
}
36+
37+
/**
38+
* @param token The conversation token
39+
* @param pollId Id of the poll
40+
*/
41+
const getPollData = async (token: string, pollId: string): getPollResponse => {
42+
return axios.get(generateOcsUrl('apps/spreed/api/v1/poll/{token}/{pollId}', { token, pollId }))
43+
}
44+
45+
/**
46+
* @param token The conversation token
47+
* @param pollId Id of the poll
48+
* @param optionIds Indexes of options the participant votes for
49+
*/
50+
const submitVote = async (token: string, pollId: string, optionIds: votePollParams['optionIds']): votePollResponse => {
51+
return axios.post(generateOcsUrl('apps/spreed/api/v1/poll/{token}/{pollId}', { token, pollId }), {
52+
optionIds,
53+
} as votePollParams)
54+
}
55+
56+
/**
57+
* @param token The conversation token
58+
* @param pollId Id of the poll
59+
*/
60+
const endPoll = async (token: string, pollId: string): closePollResponse => {
61+
return axios.delete(generateOcsUrl('apps/spreed/api/v1/poll/{token}/{pollId}', { token, pollId }))
62+
}
63+
64+
export {
65+
createPoll,
66+
getPollData,
67+
submitVote,
68+
endPoll,
69+
}

src/store/messagesStore.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
} from '../services/messagesService.ts'
3131
import { useChatExtrasStore } from '../stores/chatExtras.js'
3232
import { useGuestNameStore } from '../stores/guestName.js'
33-
import { usePollsStore } from '../stores/polls.js'
33+
import { usePollsStore } from '../stores/polls.ts'
3434
import { useReactionsStore } from '../stores/reactions.js'
3535
import { useSharedItemsStore } from '../stores/sharedItems.js'
3636
import CancelableRequest from '../utils/cancelableRequest.js'

src/stores/__tests__/polls.spec.js

+14-9
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ import flushPromises from 'flush-promises'
66
import { setActivePinia, createPinia } from 'pinia'
77

88
import { ATTENDEE } from '../../constants.js'
9-
import pollService from '../../services/pollService.js'
9+
import {
10+
createPoll,
11+
getPollData,
12+
submitVote,
13+
endPoll,
14+
} from '../../services/pollService.ts'
1015
import { generateOCSResponse } from '../../test-helpers.js'
11-
import { usePollsStore } from '../polls.js'
16+
import { usePollsStore } from '../polls.ts'
1217

13-
jest.mock('../../services/pollService.js', () => ({
14-
postNewPoll: jest.fn(),
18+
jest.mock('../../services/pollService', () => ({
19+
createPoll: jest.fn(),
1520
getPollData: jest.fn(),
1621
submitVote: jest.fn(),
1722
endPoll: jest.fn(),
@@ -88,7 +93,7 @@ describe('pollsStore', () => {
8893
it('receives a poll from server and adds it to the store', async () => {
8994
// Arrange
9095
const response = generateOCSResponse({ payload: poll })
91-
pollService.getPollData.mockResolvedValue(response)
96+
getPollData.mockResolvedValue(response)
9297

9398
// Act
9499
await pollsStore.getPollData({ token: TOKEN, pollId: poll.id })
@@ -101,7 +106,7 @@ describe('pollsStore', () => {
101106
// Arrange
102107
jest.useFakeTimers()
103108
const response = generateOCSResponse({ payload: poll })
104-
pollService.getPollData.mockResolvedValue(response)
109+
getPollData.mockResolvedValue(response)
105110

106111
// Act
107112
pollsStore.debounceGetPollData({ token: TOKEN, pollId: poll.id })
@@ -116,7 +121,7 @@ describe('pollsStore', () => {
116121
it('creates a poll and adds it to the store', async () => {
117122
// Arrange
118123
const response = generateOCSResponse({ payload: poll })
119-
pollService.postNewPoll.mockResolvedValue(response)
124+
createPoll.mockResolvedValue(response)
120125

121126
// Act
122127
await pollsStore.createPoll({ token: TOKEN, ...pollRequest })
@@ -129,7 +134,7 @@ describe('pollsStore', () => {
129134
// Arrange
130135
pollsStore.addPoll({ token: TOKEN, poll })
131136
const response = generateOCSResponse({ payload: pollWithVote })
132-
pollService.submitVote.mockResolvedValue(response)
137+
submitVote.mockResolvedValue(response)
133138

134139
// Act
135140
await pollsStore.submitVote({ token: TOKEN, pollId: poll.id, optionIds: [0] })
@@ -142,7 +147,7 @@ describe('pollsStore', () => {
142147
// Arrange
143148
pollsStore.addPoll({ token: TOKEN, poll: pollWithVote })
144149
const response = generateOCSResponse({ payload: pollWithVoteEnded })
145-
pollService.endPoll.mockResolvedValue(response)
150+
endPoll.mockResolvedValue(response)
146151

147152
// Act
148153
await pollsStore.endPoll({ token: TOKEN, pollId: poll.id })

src/stores/polls.js renamed to src/stores/polls.ts

+37-19
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,55 @@ import Vue from 'vue'
99
import { showError, showInfo, TOAST_PERMANENT_TIMEOUT } from '@nextcloud/dialogs'
1010
import { t } from '@nextcloud/l10n'
1111

12-
import pollService from '../services/pollService.js'
13-
12+
import {
13+
createPoll,
14+
getPollData,
15+
submitVote,
16+
endPoll,
17+
} from '../services/pollService.ts'
18+
import type {
19+
ChatMessage,
20+
createPollParams,
21+
Poll, votePollParams
22+
} from '../types/index.ts'
23+
24+
type createPollPayload = { token: string } & createPollParams
25+
type submitVotePayload = { token: string, pollId: string } & Pick<votePollParams, 'optionIds'>
26+
type State = {
27+
polls: Record<string, Record<string, Poll>>,
28+
debouncedFunctions: Record<string, Record<string, () => void>>,
29+
activePoll: null,
30+
pollToastsQueue: Record<string, ReturnType<typeof showInfo>>,
31+
}
1432
export const usePollsStore = defineStore('polls', {
15-
state: () => ({
33+
state: (): State => ({
1634
polls: {},
1735
debouncedFunctions: {},
1836
activePoll: null,
1937
pollToastsQueue: {},
2038
}),
2139

2240
getters: {
23-
getPoll: (state) => (token, pollId) => {
41+
getPoll: (state) => (token: string, pollId: string): Poll => {
2442
return state.polls[token]?.[pollId]
2543
},
2644

27-
isNewPoll: (state) => (pollId) => {
45+
isNewPoll: (state) => (pollId: number) => {
2846
return state.pollToastsQueue[pollId] !== undefined
2947
},
3048
},
3149

3250
actions: {
33-
addPoll({ token, poll }) {
51+
addPoll({ token, poll }: { token: string, poll: Poll }) {
3452
if (!this.polls[token]) {
3553
Vue.set(this.polls, token, {})
3654
}
3755
Vue.set(this.polls[token], poll.id, poll)
3856
},
3957

40-
async getPollData({ token, pollId }) {
58+
async getPollData({ token, pollId }: { token: string, pollId: string }) {
4159
try {
42-
const response = await pollService.getPollData(token, pollId)
60+
const response = await getPollData(token, pollId)
4361
this.addPoll({ token, poll: response.data.ocs.data })
4462
} catch (error) {
4563
console.error(error)
@@ -55,7 +73,7 @@ export const usePollsStore = defineStore('polls', {
5573
* @param { string } root0.token The token of the conversation
5674
* @param { number } root0.pollId The id of the poll
5775
*/
58-
debounceGetPollData({ token, pollId }) {
76+
debounceGetPollData({ token, pollId }: { token: string, pollId: string }) {
5977
if (!this.debouncedFunctions[token]) {
6078
Vue.set(this.debouncedFunctions, token, {})
6179
}
@@ -70,15 +88,15 @@ export const usePollsStore = defineStore('polls', {
7088
this.debouncedFunctions[token][pollId]()
7189
},
7290

73-
async createPoll({ token, question, options, resultMode, maxVotes }) {
91+
async createPoll({ token, question, options, resultMode, maxVotes }: createPollPayload) {
7492
try {
75-
const response = await pollService.postNewPoll(
93+
const response = await createPoll({
7694
token,
7795
question,
7896
options,
7997
resultMode,
8098
maxVotes,
81-
)
99+
})
82100
this.addPoll({ token, poll: response.data.ocs.data })
83101

84102
return response.data.ocs.data
@@ -87,27 +105,27 @@ export const usePollsStore = defineStore('polls', {
87105
}
88106
},
89107

90-
async submitVote({ token, pollId, optionIds }) {
108+
async submitVote({ token, pollId, optionIds }: submitVotePayload) {
91109
try {
92-
const response = await pollService.submitVote(token, pollId, optionIds)
110+
const response = await submitVote(token, pollId, optionIds)
93111
this.addPoll({ token, poll: response.data.ocs.data })
94112
} catch (error) {
95113
console.error(error)
96114
showError(t('spreed', 'An error occurred while submitting your vote'))
97115
}
98116
},
99117

100-
async endPoll({ token, pollId }) {
118+
async endPoll({ token, pollId }: { token: string, pollId: string }) {
101119
try {
102-
const response = await pollService.endPoll(token, pollId)
120+
const response = await endPoll(token, pollId)
103121
this.addPoll({ token, poll: response.data.ocs.data })
104122
} catch (error) {
105123
console.error(error)
106124
showError(t('spreed', 'An error occurred while ending the poll'))
107125
}
108126
},
109127

110-
setActivePoll({ token, pollId, name }) {
128+
setActivePoll({ token, pollId, name }: { token: string, pollId: string, name: string }) {
111129
Vue.set(this, 'activePoll', { token, id: pollId, name })
112130
},
113131

@@ -117,7 +135,7 @@ export const usePollsStore = defineStore('polls', {
117135
}
118136
},
119137

120-
addPollToast({ token, message }) {
138+
addPollToast({ token, message }: { token: string, message: ChatMessage }) {
121139
const pollId = message.messageParameters.object.id
122140
const name = message.messageParameters.object.name
123141

@@ -136,7 +154,7 @@ export const usePollsStore = defineStore('polls', {
136154
Vue.set(this.pollToastsQueue, pollId, toast)
137155
},
138156

139-
hidePollToast(pollId) {
157+
hidePollToast(pollId: string) {
140158
if (this.pollToastsQueue[pollId]) {
141159
this.pollToastsQueue[pollId].hideToast()
142160
Vue.delete(this.pollToastsQueue, pollId)

0 commit comments

Comments
 (0)