refs #884 Add request loading circle in new toot modal

This commit is contained in:
AkiraFukushima 2019-05-07 23:22:01 +09:00
parent 327f621791
commit 7a1d9ed05b
3 changed files with 161 additions and 124 deletions

View File

@ -4,20 +4,15 @@
:visible.sync="newTootModal" :visible.sync="newTootModal"
:before-close="closeConfirm" :before-close="closeConfirm"
width="400px" width="400px"
class="new-toot-modal"> class="new-toot-modal"
>
<el-form v-on:submit.prevent="toot" role="form"> <el-form v-on:submit.prevent="toot" role="form">
<div class="spoiler" v-show="showContentWarning"> <div class="spoiler" v-show="showContentWarning">
<div class="el-input"> <div class="el-input">
<input type="text" class="el-input__inner" :placeholder="$t('modals.new_toot.cw')" v-model="spoiler" v-shortkey.avoid /> <input type="text" class="el-input__inner" :placeholder="$t('modals.new_toot.cw')" v-model="spoiler" v-shortkey.avoid />
</div> </div>
</div> </div>
<Status <Status v-model="status" :opened="newTootModal" :fixCursorPos="hashtagInserting" @paste="onPaste" @toot="toot" />
v-model="status"
:opened="newTootModal"
:fixCursorPos="hashtagInserting"
@paste="onPaste"
@toot="toot"
/>
</el-form> </el-form>
<div class="preview"> <div class="preview">
<div class="image-wrapper" v-for="media in attachedMedias" v-bind:key="media.id"> <div class="image-wrapper" v-for="media in attachedMedias" v-bind:key="media.id">
@ -28,11 +23,12 @@
class="image-description" class="image-description"
:placeholder="$t('modals.new_toot.description')" :placeholder="$t('modals.new_toot.description')"
v-model="mediaDescriptions[media.id]" v-model="mediaDescriptions[media.id]"
v-shortkey="{left: ['arrowleft'], right: ['arrowright']}" v-shortkey="{ left: ['arrowleft'], right: ['arrowright'] }"
@shortkey="handleDescriptionKey" @shortkey="handleDescriptionKey"
role="textbox" role="textbox"
contenteditable="true" contenteditable="true"
aria-multiline="true"> aria-multiline="true"
>
</textarea> </textarea>
</div> </div>
</div> </div>
@ -41,7 +37,7 @@
<el-button size="small" type="text" @click="selectImage" :title="$t('modals.new_toot.add_image')"> <el-button size="small" type="text" @click="selectImage" :title="$t('modals.new_toot.add_image')">
<icon name="camera"></icon> <icon name="camera"></icon>
</el-button> </el-button>
<input name="image" type="file" class="image-input" ref="image" @change="onChangeImage" :key="attachedMediaId"/> <input name="image" type="file" class="image-input" ref="image" @change="onChangeImage" :key="attachedMediaId" />
</div> </div>
<div class="privacy"> <div class="privacy">
<el-dropdown trigger="click" @command="changeVisibility"> <el-dropdown trigger="click" @command="changeVisibility">
@ -69,24 +65,50 @@
</el-dropdown> </el-dropdown>
</div> </div>
<div class="sensitive" v-show="attachedMedias.length > 0"> <div class="sensitive" v-show="attachedMedias.length > 0">
<el-button size="small" type="text" @click="changeSensitive" :title="$t('modals.new_toot.change_sensitive')" :aria-pressed="sensitive"> <el-button
size="small"
type="text"
@click="changeSensitive"
:title="$t('modals.new_toot.change_sensitive')"
:aria-pressed="sensitive"
>
<icon name="eye-slash" v-show="!sensitive"></icon> <icon name="eye-slash" v-show="!sensitive"></icon>
<icon name="eye" v-show="sensitive"></icon> <icon name="eye" v-show="sensitive"></icon>
</el-button> </el-button>
</div> </div>
<div class="content-warning"> <div class="content-warning">
<el-button size="small" type="text" @click="showContentWarning = !showContentWarning" :title="$t('modals.new_toot.add_cw')" :class="showContentWarning? '' : 'clickable'" :aria-pressed="showContentWarning"> <el-button
size="small"
type="text"
@click="showContentWarning = !showContentWarning"
:title="$t('modals.new_toot.add_cw')"
:class="showContentWarning ? '' : 'clickable'"
:aria-pressed="showContentWarning"
>
<span class="cw-text">CW</span> <span class="cw-text">CW</span>
</el-button> </el-button>
</div> </div>
<div class="pined-hashtag"> <div class="pined-hashtag">
<el-button size="small" type="text" @click="pinedHashtag = !pinedHashtag" :title="$t('modals.new_toot.pined_hashtag')" :class="pinedHashtag? '' : 'clickable'" :aria-pressed="pinedHashtag"> <el-button
size="small"
type="text"
@click="pinedHashtag = !pinedHashtag"
:title="$t('modals.new_toot.pined_hashtag')"
:class="pinedHashtag ? '' : 'clickable'"
:aria-pressed="pinedHashtag"
>
<icon name="hashtag"></icon> <icon name="hashtag"></icon>
</el-button> </el-button>
</div> </div>
<span class="text-count">{{ tootMax - status.length }}</span> <div class="info">
<el-button class="toot-action" size="small" @click="closeConfirm(close)">{{ $t('modals.new_toot.cancel') }}</el-button> <img src="../../../assets/images/loading-spinner-wide.svg" v-show="loading" class="loading" />
<el-button class="toot-action" size="small" type="primary" @click="toot" :loading="blockSubmit">{{ $t('modals.new_toot.toot') }}</el-button> <span class="text-count">{{ tootMax - status.length }}</span>
<el-button class="toot-action" size="small" @click="closeConfirm(close)">{{ $t('modals.new_toot.cancel') }}</el-button>
<el-button class="toot-action" size="small" type="primary" @click="toot" :loading="blockSubmit">{{
$t('modals.new_toot.toot')
}}</el-button>
</div>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</el-dialog> </el-dialog>
@ -103,7 +125,7 @@ export default {
components: { components: {
Status Status
}, },
data () { data() {
return { return {
status: '', status: '',
mediaDescriptions: {}, mediaDescriptions: {},
@ -114,7 +136,7 @@ export default {
}, },
computed: { computed: {
...mapState('TimelineSpace/Modals/NewToot', { ...mapState('TimelineSpace/Modals/NewToot', {
replyToId: (state) => { replyToId: state => {
if (state.replyToMessage !== null) { if (state.replyToMessage !== null) {
return state.replyToMessage.id return state.replyToMessage.id
} else { } else {
@ -128,7 +150,7 @@ export default {
sensitive: state => state.sensitive, sensitive: state => state.sensitive,
initialStatus: state => state.initialStatus, initialStatus: state => state.initialStatus,
initialSpoiler: state => state.initialSpoiler, initialSpoiler: state => state.initialSpoiler,
visibilityIcon: (state) => { visibilityIcon: state => {
switch (state.visibility) { switch (state.visibility) {
case Visibility.Public.value: case Visibility.Public.value:
return 'globe' return 'globe'
@ -141,19 +163,18 @@ export default {
default: default:
return 'globe' return 'globe'
} }
} },
loading: state => state.loading
}), }),
...mapState('TimelineSpace', { ...mapState('TimelineSpace', {
tootMax: state => state.tootMax tootMax: state => state.tootMax
}), }),
...mapGetters('TimelineSpace/Modals/NewToot', [ ...mapGetters('TimelineSpace/Modals/NewToot', ['hashtagInserting']),
'hashtagInserting'
]),
newTootModal: { newTootModal: {
get () { get() {
return this.$store.state.TimelineSpace.Modals.NewToot.modalOpen return this.$store.state.TimelineSpace.Modals.NewToot.modalOpen
}, },
set (value) { set(value) {
if (value) { if (value) {
this.$store.dispatch('TimelineSpace/Modals/NewToot/openModal') this.$store.dispatch('TimelineSpace/Modals/NewToot/openModal')
} else { } else {
@ -162,16 +183,19 @@ export default {
} }
}, },
pinedHashtag: { pinedHashtag: {
get () { get() {
return this.$store.state.TimelineSpace.Modals.NewToot.pinedHashtag return this.$store.state.TimelineSpace.Modals.NewToot.pinedHashtag
}, },
set (value) { set(value) {
this.$store.commit('TimelineSpace/Modals/NewToot/changePinedHashtag', value) this.$store.commit('TimelineSpace/Modals/NewToot/changePinedHashtag', value)
} }
} }
}, },
created() {
this.$store.dispatch('TimelineSpace/Modals/NewToot/setupLoading')
},
watch: { watch: {
newTootModal: function (newState, oldState) { newTootModal: function(newState, oldState) {
if (!oldState && newState) { if (!oldState && newState) {
this.showContentWarning = this.initialSpoiler this.showContentWarning = this.initialSpoiler
this.status = this.initialStatus this.status = this.initialStatus
@ -180,12 +204,12 @@ export default {
} }
}, },
methods: { methods: {
close () { close() {
this.filteredAccount = [] this.filteredAccount = []
this.$store.dispatch('TimelineSpace/Modals/NewToot/resetMediaId') this.$store.dispatch('TimelineSpace/Modals/NewToot/resetMediaId')
this.$store.dispatch('TimelineSpace/Modals/NewToot/closeModal') this.$store.dispatch('TimelineSpace/Modals/NewToot/closeModal')
}, },
async toot () { async toot() {
if (!this.newTootModal) { if (!this.newTootModal) {
return return
} }
@ -195,7 +219,7 @@ export default {
type: 'error' type: 'error'
}) })
} }
const visibilityKey = Object.keys(Visibility).find((key) => { const visibilityKey = Object.keys(Visibility).find(key => {
return Visibility[key].value === this.visibility return Visibility[key].value === this.visibility
}) })
let form = { let form = {
@ -217,15 +241,18 @@ export default {
}) })
} }
form = Object.assign(form, { form = Object.assign(form, {
media_ids: this.attachedMedias.map((m) => { return m.id }) media_ids: this.attachedMedias.map(m => {
return m.id
})
}) })
} }
const status = await this.$store.dispatch('TimelineSpace/Modals/NewToot/updateMedia', this.mediaDescriptions) const status = await this.$store
.dispatch('TimelineSpace/Modals/NewToot/updateMedia', this.mediaDescriptions)
.then(() => { .then(() => {
return this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form) return this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form)
}) })
.catch((e) => { .catch(e => {
console.error(e) console.error(e)
this.$message({ this.$message({
message: this.$t('message.toot_error'), message: this.$t('message.toot_error'),
@ -235,10 +262,10 @@ export default {
this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags) this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags)
this.close() this.close()
}, },
selectImage () { selectImage() {
this.$refs.image.click() this.$refs.image.click()
}, },
onChangeImage (e) { onChangeImage(e) {
if (e.target.files.item(0) === null || e.target.files.item(0) === undefined) { if (e.target.files.item(0) === null || e.target.files.item(0) === undefined) {
return return
} }
@ -252,7 +279,7 @@ export default {
} }
this.updateImage(file) this.updateImage(file)
}, },
onPaste (e) { onPaste(e) {
const mimeTypes = clipboard.availableFormats().filter(type => type.startsWith('image')) const mimeTypes = clipboard.availableFormats().filter(type => type.startsWith('image'))
if (mimeTypes.length === 0) { if (mimeTypes.length === 0) {
return return
@ -268,43 +295,40 @@ export default {
const file = new File([data], 'clipboard.picture', { type: mimeTypes[0] }) const file = new File([data], 'clipboard.picture', { type: mimeTypes[0] })
this.updateImage(file) this.updateImage(file)
}, },
updateImage (file) { updateImage(file) {
this.$store.dispatch('TimelineSpace/Modals/NewToot/incrementMediaId') this.$store.dispatch('TimelineSpace/Modals/NewToot/incrementMediaId')
this.$store.dispatch('TimelineSpace/Modals/NewToot/uploadImage', file) this.$store.dispatch('TimelineSpace/Modals/NewToot/uploadImage', file).catch(() => {
.catch(() => { this.$message({
this.$message({ message: this.$t('message.attach_error'),
message: this.$t('message.attach_error'), type: 'error'
type: 'error'
})
}) })
})
}, },
removeAttachment (media) { removeAttachment(media) {
this.$store.commit('TimelineSpace/Modals/NewToot/removeMedia', media) this.$store.commit('TimelineSpace/Modals/NewToot/removeMedia', media)
delete this.mediaDescriptions[media.id] delete this.mediaDescriptions[media.id]
}, },
changeVisibility (level) { changeVisibility(level) {
this.$store.commit('TimelineSpace/Modals/NewToot/changeVisibilityValue', level) this.$store.commit('TimelineSpace/Modals/NewToot/changeVisibilityValue', level)
}, },
changeSensitive () { changeSensitive() {
this.$store.commit('TimelineSpace/Modals/NewToot/changeSensitive', !this.sensitive) this.$store.commit('TimelineSpace/Modals/NewToot/changeSensitive', !this.sensitive)
}, },
closeConfirm (done) { closeConfirm(done) {
if (this.status.length === 0) { if (this.status.length === 0) {
done() done()
} else { } else {
this.$confirm( this.$confirm(this.$t('modals.new_toot.close_confirm'), {
this.$t('modals.new_toot.close_confirm'), confirmButtonText: this.$t('modals.new_toot.close_confirm_ok'),
{ cancelButtonText: this.$t('modals.new_toot.close_confirm_cancel')
confirmButtonText: this.$t('modals.new_toot.close_confirm_ok'), })
cancelButtonText: this.$t('modals.new_toot.close_confirm_cancel')
})
.then(_ => { .then(_ => {
done() done()
}) })
.catch(_ => {}) .catch(_ => {})
} }
}, },
handleDescriptionKey (event) { handleDescriptionKey(event) {
const current = event.target.selectionStart const current = event.target.selectionStart
switch (event.srcKey) { switch (event.srcKey) {
case 'left': case 'left':
@ -451,9 +475,20 @@ export default {
color: #909399; color: #909399;
} }
.text-count { .info {
padding-right: 10px; display: flex;
color: #909399; justify-content: flex-end;
align-items: center;
.loading {
width: 18px;
margin-right: 4px;
}
.text-count {
padding-right: 10px;
color: #909399;
}
} }
.toot-action { .toot-action {

View File

@ -4,19 +4,21 @@ import Visibility, { VisibilityType } from '~/src/constants/visibility'
import TootStatus, { StatusState } from './NewToot/Status' import TootStatus, { StatusState } from './NewToot/Status'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex' import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store' import { RootState } from '@/store'
import AxiosLoading from '@/utils/axiosLoading'
export interface NewTootState { export interface NewTootState {
modalOpen: boolean, modalOpen: boolean
initialStatus: string, initialStatus: string
initialSpoiler: string, initialSpoiler: string
replyToMessage: Status | null, replyToMessage: Status | null
blockSubmit: boolean, blockSubmit: boolean
attachedMedias: Array<Attachment>, attachedMedias: Array<Attachment>
visibility: number, visibility: number
sensitive: boolean, sensitive: boolean
attachedMediaId: number, attachedMediaId: number
pinedHashtag: boolean, pinedHashtag: boolean
hashtags: Array<Tag> hashtags: Array<Tag>
loading: boolean
} }
export interface NewTootModuleState extends NewTootState { export interface NewTootModuleState extends NewTootState {
@ -34,7 +36,8 @@ const state = (): NewTootState => ({
sensitive: false, sensitive: false,
attachedMediaId: 0, attachedMediaId: 0,
pinedHashtag: false, pinedHashtag: false,
hashtags: [] hashtags: [],
loading: false
}) })
export const MUTATION_TYPES = { export const MUTATION_TYPES = {
@ -50,7 +53,8 @@ export const MUTATION_TYPES = {
CHANGE_SENSITIVE: 'changeSensitive', CHANGE_SENSITIVE: 'changeSensitive',
UPDATE_MEDIA_ID: 'updateMediaId', UPDATE_MEDIA_ID: 'updateMediaId',
CHANGE_PINED_HASHTAG: 'changePinedHashtag', CHANGE_PINED_HASHTAG: 'changePinedHashtag',
UPDATE_HASHTAGS: 'updateHashtags' UPDATE_HASHTAGS: 'updateHashtags',
CHANGE_LOADING: 'changeLoading'
} }
const mutations: MutationTree<NewTootState> = { const mutations: MutationTree<NewTootState> = {
@ -72,7 +76,7 @@ const mutations: MutationTree<NewTootState> = {
[MUTATION_TYPES.APPEND_ATTACHED_MEDIAS]: (state, media: Attachment) => { [MUTATION_TYPES.APPEND_ATTACHED_MEDIAS]: (state, media: Attachment) => {
state.attachedMedias = state.attachedMedias.concat([media]) state.attachedMedias = state.attachedMedias.concat([media])
}, },
[MUTATION_TYPES.CLEAR_ATTACHED_MEDIAS]: (state) => { [MUTATION_TYPES.CLEAR_ATTACHED_MEDIAS]: state => {
state.attachedMedias = [] state.attachedMedias = []
}, },
[MUTATION_TYPES.REMOVE_MEDIA]: (state, media: Attachment) => { [MUTATION_TYPES.REMOVE_MEDIA]: (state, media: Attachment) => {
@ -98,26 +102,34 @@ const mutations: MutationTree<NewTootState> = {
}, },
[MUTATION_TYPES.UPDATE_HASHTAGS]: (state, tags: Array<Tag>) => { [MUTATION_TYPES.UPDATE_HASHTAGS]: (state, tags: Array<Tag>) => {
state.hashtags = tags state.hashtags = tags
},
[MUTATION_TYPES.CHANGE_LOADING]: (state, value: boolean) => {
state.loading = value
} }
} }
const actions: ActionTree<NewTootState, RootState> = { const actions: ActionTree<NewTootState, RootState> = {
setupLoading: ({ commit }) => {
const axiosLoading = new AxiosLoading()
axiosLoading.on('start', (_: number) => {
commit(MUTATION_TYPES.CHANGE_LOADING, true)
})
axiosLoading.on('done', () => {
commit(MUTATION_TYPES.CHANGE_LOADING, false)
})
},
updateMedia: async ({ rootState }, media: Attachment) => { updateMedia: async ({ rootState }, media: Attachment) => {
if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) {
throw new AuthenticationError() throw new AuthenticationError()
} }
const client = new Mastodon( const client = new Mastodon(rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1')
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const attachments = Object.keys(media).map(async id => { const attachments = Object.keys(media).map(async id => {
return client.put<Attachment>(`/media/${id}`, { description: media[id] }) return client.put<Attachment>(`/media/${id}`, { description: media[id] })
}) })
return Promise.all(attachments) return Promise.all(attachments).catch(err => {
.catch(err => { console.error(err)
console.error(err) throw err
throw err })
})
}, },
postToot: async ({ state, commit, rootState }, form) => { postToot: async ({ state, commit, rootState }, form) => {
if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) {
@ -127,11 +139,9 @@ const actions: ActionTree<NewTootState, RootState> = {
return return
} }
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true) commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true)
const client = new Mastodon( const client = new Mastodon(rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1')
rootState.TimelineSpace.account.accessToken, return client
rootState.TimelineSpace.account.baseURL + '/api/v1' .post<Status>('/statuses', form)
)
return client.post<Status>('/statuses', form)
.then((res: Response<Status>) => { .then((res: Response<Status>) => {
ipcRenderer.send('toot-action-sound') ipcRenderer.send('toot-action-sound')
return res.data return res.data
@ -142,9 +152,10 @@ const actions: ActionTree<NewTootState, RootState> = {
}, },
openReply: ({ commit, rootState }, message: Status) => { openReply: ({ commit, rootState }, message: Status) => {
commit(MUTATION_TYPES.SET_REPLY_TO, message) commit(MUTATION_TYPES.SET_REPLY_TO, message)
const mentionAccounts = [message.account.acct].concat(message.mentions.map(a => a.acct)) const mentionAccounts = [message.account.acct]
.concat(message.mentions.map(a => a.acct))
.filter((a, i, self) => self.indexOf(a) === i) .filter((a, i, self) => self.indexOf(a) === i)
.filter((a) => a !== rootState.TimelineSpace.account.username) .filter(a => a !== rootState.TimelineSpace.account.username)
commit(MUTATION_TYPES.UPDATE_INITIAL_STATUS, `${mentionAccounts.map(m => `@${m}`).join(' ')} `) commit(MUTATION_TYPES.UPDATE_INITIAL_STATUS, `${mentionAccounts.map(m => `@${m}`).join(' ')} `)
commit(MUTATION_TYPES.UPDATE_INITIAL_SPOILER, message.spoiler_text) commit(MUTATION_TYPES.UPDATE_INITIAL_SPOILER, message.spoiler_text)
commit(MUTATION_TYPES.CHANGE_MODAL, true) commit(MUTATION_TYPES.CHANGE_MODAL, true)
@ -179,13 +190,11 @@ const actions: ActionTree<NewTootState, RootState> = {
if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) { if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) {
throw new AuthenticationError() throw new AuthenticationError()
} }
const client = new Mastodon( const client = new Mastodon(rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1')
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const formData = new FormData() const formData = new FormData()
formData.append('file', image) formData.append('file', image)
return client.post<Attachment>('/media', formData) return client
.post<Attachment>('/media', formData)
.then(res => { .then(res => {
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false) commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false)
if (res.data.type === 'unknown') throw new UnknownTypeError() if (res.data.type === 'unknown') throw new UnknownTypeError()
@ -210,12 +219,9 @@ const actions: ActionTree<NewTootState, RootState> = {
} }
}, },
fetchVisibility: async ({ commit, rootState }) => { fetchVisibility: async ({ commit, rootState }) => {
const client = new Mastodon( const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Account> = await client.get<Account>('/accounts/verify_credentials') const res: Response<Account> = await client.get<Account>('/accounts/verify_credentials')
const visibility: VisibilityType | undefined = (Object.values(Visibility) as Array<VisibilityType>).find((v) => { const visibility: VisibilityType | undefined = (Object.values(Visibility) as Array<VisibilityType>).find(v => {
return v.key === res.data.source!.privacy return v.key === res.data.source!.privacy
}) })
if (visibility === undefined) { if (visibility === undefined) {
@ -227,7 +233,7 @@ const actions: ActionTree<NewTootState, RootState> = {
} }
const getters: GetterTree<NewTootState, RootState> = { const getters: GetterTree<NewTootState, RootState> = {
hashtagInserting: (state) => { hashtagInserting: state => {
return !state.replyToMessage && state.pinedHashtag return !state.replyToMessage && state.pinedHashtag
} }
} }

View File

@ -3,7 +3,7 @@ import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store/index' import { RootState } from '@/store/index'
interface Suggest { interface Suggest {
name: string, name: string
image: string | null image: string | null
} }
@ -12,7 +12,7 @@ interface SuggestAccount extends Suggest {}
interface SuggestHashtag extends Suggest {} interface SuggestHashtag extends Suggest {}
export interface StatusState { export interface StatusState {
filteredAccounts: Array<SuggestAccount>, filteredAccounts: Array<SuggestAccount>
filteredHashtags: Array<SuggestHashtag> filteredHashtags: Array<SuggestHashtag>
} }
@ -25,7 +25,7 @@ export const MUTATION_TYPES = {
UPDATE_FILTERED_ACCOUNTS: 'updateFilteredAccounts', UPDATE_FILTERED_ACCOUNTS: 'updateFilteredAccounts',
CLEAR_FILTERED_ACCOUNTS: 'clearFilteredAccounts', CLEAR_FILTERED_ACCOUNTS: 'clearFilteredAccounts',
UPDATE_FILTERED_HASHTAGS: 'updateFilteredHashtags', UPDATE_FILTERED_HASHTAGS: 'updateFilteredHashtags',
CLAER_FILTERED_HASHTAGS: 'clearFilteredHashtags' CLEAR_FILTERED_HASHTAGS: 'clearFilteredHashtags'
} }
const mutations: MutationTree<StatusState> = { const mutations: MutationTree<StatusState> = {
@ -35,7 +35,7 @@ const mutations: MutationTree<StatusState> = {
image: null image: null
})) }))
}, },
[MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: (state) => { [MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: state => {
state.filteredAccounts = [] state.filteredAccounts = []
}, },
[MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS]: (state, tags: Array<Tag>) => { [MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS]: (state, tags: Array<Tag>) => {
@ -44,27 +44,21 @@ const mutations: MutationTree<StatusState> = {
image: null image: null
})) }))
}, },
[MUTATION_TYPES.CLEAR_FILTERED_ACCOUNTS]: (state) => { [MUTATION_TYPES.CLEAR_FILTERED_HASHTAGS]: state => {
state.filteredHashtags = [] state.filteredHashtags = []
} }
} }
const actions: ActionTree<StatusState, RootState> = { const actions: ActionTree<StatusState, RootState> = {
searchAccount: async ({ commit, rootState }, word: string) => { searchAccount: async ({ commit, rootState }, word: string) => {
const client = new Mastodon( const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Results> = await client.get<Results>('/search', { q: word, resolve: false }) const res: Response<Results> = await client.get<Results>('/search', { q: word, resolve: false })
commit(MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS, res.data.accounts) commit(MUTATION_TYPES.UPDATE_FILTERED_ACCOUNTS, res.data.accounts)
if (res.data.accounts.length === 0) throw new Error('Empty') if (res.data.accounts.length === 0) throw new Error('Empty')
return res.data.accounts return res.data.accounts
}, },
searchHashtag: async ({ commit, rootState }, word: string) => { searchHashtag: async ({ commit, rootState }, word: string) => {
const client = new Mastodon( const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
rootState.TimelineSpace.account.accessToken!,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
const res: Response<Results> = await client.get<Results>('/search', { q: word }) const res: Response<Results> = await client.get<Results>('/search', { q: word })
commit(MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS, res.data.hashtags) commit(MUTATION_TYPES.UPDATE_FILTERED_HASHTAGS, res.data.hashtags)
if (res.data.hashtags.length === 0) throw new Error('Empty') if (res.data.hashtags.length === 0) throw new Error('Empty')
@ -74,18 +68,20 @@ const actions: ActionTree<StatusState, RootState> = {
const getters: GetterTree<StatusState, RootState> = { const getters: GetterTree<StatusState, RootState> = {
pickerEmojis: (_state, _getters, rootState) => { pickerEmojis: (_state, _getters, rootState) => {
return rootState.TimelineSpace.emojis.filter((e, i, array) => { return rootState.TimelineSpace.emojis
return (array.findIndex(ar => e.name === ar.name) === i) .filter((e, i, array) => {
}).map(e => { return array.findIndex(ar => e.name === ar.name) === i
return { })
name: e.name, .map(e => {
short_names: [e.name], return {
text: e.name, name: e.name,
emoticons: [], short_names: [e.name],
keywords: [e.name], text: e.name,
imageUrl: e.image emoticons: [],
} keywords: [e.name],
}) imageUrl: e.image
}
})
} }
} }