Merge pull request #914 from h3poteto/refactor/new-toot

refactor: Move logics to vuex store in new toot
This commit is contained in:
AkiraFukushima 2019-05-15 22:58:01 +09:00 committed by GitHub
commit 50948a03c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 135 additions and 55 deletions

View File

@ -22,7 +22,8 @@
maxlength="420"
class="image-description"
:placeholder="$t('modals.new_toot.description')"
v-model="mediaDescriptions[media.id]"
:value="mediaDescriptions[media.id]"
@input="updateDescription(media.id, $event.target.value)"
v-shortkey="{ left: ['arrowleft'], right: ['arrowright'] }"
@shortkey="handleDescriptionKey"
role="textbox"
@ -119,6 +120,7 @@ import { mapState, mapGetters } from 'vuex'
import { clipboard } from 'electron'
import Visibility from '~/src/constants/visibility'
import Status from './NewToot/Status'
import { NewTootTootLength, NewTootAttachLength, NewTootModalOpen, NewTootBlockSubmit } from '@/errors/validations'
export default {
name: 'new-toot',
@ -128,7 +130,6 @@ export default {
data() {
return {
status: '',
mediaDescriptions: {},
spoiler: '',
showContentWarning: false,
visibilityList: Visibility
@ -145,6 +146,7 @@ export default {
},
attachedMedias: state => state.attachedMedias,
attachedMediaId: state => state.attachedMediaId,
mediaDescriptions: state => state.mediaDescriptions,
blockSubmit: state => state.blockSubmit,
visibility: state => state.visibility,
sensitive: state => state.sensitive,
@ -210,57 +212,36 @@ export default {
this.$store.dispatch('TimelineSpace/Modals/NewToot/closeModal')
},
async toot() {
if (!this.newTootModal) {
return
const form = {
status: this.status,
spoiler: this.spoiler
}
if (this.status.length < 1 || this.status.length > this.tootMax) {
return this.$message({
try {
await this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form)
this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags)
this.close()
} catch (err) {
console.error(err)
if (err instanceof NewTootTootLength) {
this.$message({
message: this.$t('validation.new_toot.toot_length', { min: 1, max: this.tootMax }),
type: 'error'
})
}
const visibilityKey = Object.keys(Visibility).find(key => {
return Visibility[key].value === this.visibility
})
let form = {
status: this.status,
visibility: Visibility[visibilityKey].key,
sensitive: this.sensitive,
spoiler_text: this.spoiler
}
if (this.replyToId !== null) {
form = Object.assign(form, {
in_reply_to_id: this.replyToId
})
}
if (this.attachedMedias.length > 0) {
if (this.attachedMedias.length > 4) {
return this.$message({
} else if (err instanceof NewTootAttachLength) {
this.$message({
message: this.$t('validation.new_toot.attach_length', { max: 4 }),
type: 'error'
})
}
form = Object.assign(form, {
media_ids: this.attachedMedias.map(m => {
return m.id
})
})
}
const status = await this.$store
.dispatch('TimelineSpace/Modals/NewToot/updateMedia', this.mediaDescriptions)
.then(() => {
return this.$store.dispatch('TimelineSpace/Modals/NewToot/postToot', form)
})
.catch(e => {
console.error(e)
} else if (err instanceof NewTootModalOpen || err instanceof NewTootBlockSubmit) {
// Nothing
} else {
this.$message({
message: this.$t('message.toot_error'),
type: 'error'
})
})
this.$store.dispatch('TimelineSpace/Modals/NewToot/updateHashtags', status.tags)
this.close()
}
}
},
selectImage() {
this.$refs.image.click()
@ -305,8 +286,7 @@ export default {
})
},
removeAttachment(media) {
this.$store.commit('TimelineSpace/Modals/NewToot/removeMedia', media)
delete this.mediaDescriptions[media.id]
this.$store.dispatch('TimelineSpace/Modals/NewToot/removeMedia', media)
},
changeVisibility(level) {
this.$store.commit('TimelineSpace/Modals/NewToot/changeVisibilityValue', level)
@ -340,6 +320,9 @@ export default {
default:
return true
}
},
updateDescription(id, value) {
this.$store.commit('TimelineSpace/Modals/NewToot/updateMediaDescription', { id: id, description: value })
}
}
}

View File

@ -0,0 +1,13 @@
export class NewTootModalOpen extends Error {}
export class NewTootBlockSubmit extends Error {}
export class NewTootTootLength extends Error {}
export class NewTootAttachLength extends Error {}
export class NewTootMediaDescription extends Error {}
export class NewTootUnknownType extends Error {}
export class AuthenticationError extends Error {}

View File

@ -5,6 +5,20 @@ import TootStatus, { StatusState } from './NewToot/Status'
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex'
import { RootState } from '@/store'
import AxiosLoading from '@/utils/axiosLoading'
import {
NewTootModalOpen,
NewTootBlockSubmit,
NewTootTootLength,
NewTootAttachLength,
NewTootMediaDescription,
NewTootUnknownType,
AuthenticationError
} from '@/errors/validations'
type MediaDescription = {
id: number
description: string
}
export interface NewTootState {
modalOpen: boolean
@ -13,6 +27,7 @@ export interface NewTootState {
replyToMessage: Status | null
blockSubmit: boolean
attachedMedias: Array<Attachment>
mediaDescriptions: { [key: number]: string | null }
visibility: number
sensitive: boolean
attachedMediaId: number
@ -32,6 +47,7 @@ const state = (): NewTootState => ({
replyToMessage: null,
blockSubmit: false,
attachedMedias: [],
mediaDescriptions: {},
visibility: Visibility.Public.value,
sensitive: false,
attachedMediaId: 0,
@ -49,6 +65,9 @@ export const MUTATION_TYPES = {
APPEND_ATTACHED_MEDIAS: 'appendAttachedMedias',
CLEAR_ATTACHED_MEDIAS: 'clearAttachedMedias',
REMOVE_MEDIA: 'removeMedia',
UPDATE_MEDIA_DESCRIPTION: 'updateMediaDescription',
CLEAR_MEDIA_DESCRIPTIONS: 'clearMediaDescriptions',
REMOVE_MEDIA_DESCRIPTION: 'removeMediaDescription',
CHANGE_VISIBILITY_VALUE: 'changeVisibilityValue',
CHANGE_SENSITIVE: 'changeSensitive',
UPDATE_MEDIA_ID: 'updateMediaId',
@ -82,6 +101,17 @@ const mutations: MutationTree<NewTootState> = {
[MUTATION_TYPES.REMOVE_MEDIA]: (state, media: Attachment) => {
state.attachedMedias = state.attachedMedias.filter(m => m.id !== media.id)
},
[MUTATION_TYPES.UPDATE_MEDIA_DESCRIPTION]: (state, value: MediaDescription) => {
state.mediaDescriptions[value.id] = value.description
},
[MUTATION_TYPES.CLEAR_MEDIA_DESCRIPTIONS]: state => {
state.mediaDescriptions = {}
},
[MUTATION_TYPES.REMOVE_MEDIA_DESCRIPTION]: (state, id: number) => {
const descriptions = state.mediaDescriptions
delete descriptions[id]
state.mediaDescriptions = descriptions
},
/**
* changeVisibilityValue
* Update visibility using direct value
@ -118,26 +148,74 @@ const actions: ActionTree<NewTootState, RootState> = {
commit(MUTATION_TYPES.CHANGE_LOADING, false)
})
},
updateMedia: async ({ rootState }, media: Attachment) => {
updateMedia: async ({ rootState }, mediaDescription: MediaDescription) => {
if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) {
throw new AuthenticationError()
}
const client = new Mastodon(rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1')
const attachments = Object.keys(media).map(async id => {
return client.put<Attachment>(`/media/${id}`, { description: media[id] })
const attachments = Object.keys(mediaDescription).map(async id => {
if (mediaDescription[id] !== null) {
return client.put<Attachment>(`/media/${id}`, { description: mediaDescription[id] })
} else {
return Promise.resolve({})
}
})
return Promise.all(attachments).catch(err => {
console.error(err)
throw err
})
},
postToot: async ({ state, commit, rootState }, form) => {
postToot: async ({ state, commit, rootState, dispatch }, { status, spoiler }): Promise<Status> => {
if (!state.modalOpen) {
throw new NewTootModalOpen()
}
if (status.length < 1 || status.length > rootState.TimelineSpace.tootMax) {
throw new NewTootTootLength()
}
const visibilityKey: string | undefined = Object.keys(Visibility).find(key => {
return Visibility[key].value === state.visibility
})
let specifiedVisibility: string = Visibility.Public.key
if (visibilityKey !== undefined) {
specifiedVisibility = Visibility[visibilityKey].key
}
let form = {
status: status,
visibility: specifiedVisibility,
sensitive: state.sensitive,
spoiler_text: spoiler
}
if (state.replyToMessage !== null) {
form = Object.assign(form, {
in_reply_to_id: state.replyToMessage.id
})
}
if (rootState.TimelineSpace.account.accessToken === undefined || rootState.TimelineSpace.account.accessToken === null) {
throw new AuthenticationError()
}
if (state.blockSubmit) {
return
throw new NewTootBlockSubmit()
}
if (state.attachedMedias.length > 0) {
if (state.attachedMedias.length > 4) {
throw new NewTootAttachLength()
}
form = Object.assign(form, {
media_ids: state.attachedMedias.map(m => {
return m.id
})
})
// Update media descriptions
await dispatch('updateMedia', state.mediaDescriptions).catch(_ => {
throw new NewTootMediaDescription()
})
}
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, true)
const client = new Mastodon(rootState.TimelineSpace.account.accessToken, rootState.TimelineSpace.account.baseURL + '/api/v1')
return client
@ -182,6 +260,7 @@ const actions: ActionTree<NewTootState, RootState> = {
commit(MUTATION_TYPES.SET_REPLY_TO, null)
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false)
commit(MUTATION_TYPES.CLEAR_ATTACHED_MEDIAS)
commit(MUTATION_TYPES.CLEAR_MEDIA_DESCRIPTIONS)
commit(MUTATION_TYPES.CHANGE_SENSITIVE, false)
commit(MUTATION_TYPES.CHANGE_VISIBILITY_VALUE, Visibility.Public.value)
},
@ -197,7 +276,7 @@ const actions: ActionTree<NewTootState, RootState> = {
.post<Attachment>('/media', formData)
.then(res => {
commit(MUTATION_TYPES.CHANGE_BLOCK_SUBMIT, false)
if (res.data.type === 'unknown') throw new UnknownTypeError()
if (res.data.type === 'unknown') throw new NewTootUnknownType()
commit(MUTATION_TYPES.APPEND_ATTACHED_MEDIAS, res.data)
return res.data
})
@ -210,9 +289,17 @@ const actions: ActionTree<NewTootState, RootState> = {
incrementMediaId: ({ commit, state }) => {
commit(MUTATION_TYPES.UPDATE_MEDIA_ID, state.attachedMediaId + 1)
},
decrementMediaId: ({ commit, state }) => {
commit(MUTATION_TYPES.UPDATE_MEDIA_ID, state.attachedMediaId - 1)
},
resetMediaId: ({ commit }) => {
commit(MUTATION_TYPES.UPDATE_MEDIA_ID, 0)
},
removeMedia: ({ commit, dispatch }, media: Attachment) => {
commit(MUTATION_TYPES.REMOVE_MEDIA, media)
commit(MUTATION_TYPES.REMOVE_MEDIA_DESCRIPTION, media.id)
dispatch('decrementMediaId')
},
updateHashtags: ({ commit, state }, tags: Array<Tag>) => {
if (state.pinedHashtag && tags.length > 0) {
commit(MUTATION_TYPES.UPDATE_HASHTAGS, tags)
@ -250,6 +337,3 @@ const NewToot: Module<NewTootState, RootState> = {
}
export default NewToot
class AuthenticationError {}
class UnknownTypeError {}