make reusable Exporter component

This commit is contained in:
taehoon 2019-03-30 08:03:40 -04:00
parent 0ab2f9dfa5
commit 08eaf9bd33
5 changed files with 88 additions and 39 deletions

View file

@ -0,0 +1,47 @@
const Exporter = {
props: {
getContent: {
type: Function,
required: true
},
filename: {
type: String,
default: 'export.csv'
},
exportButtonLabel: {
type: String,
default () {
return this.$t('exporter.export')
}
},
processingMessage: {
type: String,
default () {
return this.$t('exporter.processing')
}
}
},
data () {
return {
processing: false
}
},
methods: {
process () {
this.processing = true
this.getContent()
.then((content) => {
const fileToDownload = document.createElement('a')
fileToDownload.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content))
fileToDownload.setAttribute('download', this.filename)
fileToDownload.style.display = 'none'
document.body.appendChild(fileToDownload)
fileToDownload.click()
document.body.removeChild(fileToDownload)
setTimeout(() => { this.processing = false }, 2000)
})
}
}
}
export default Exporter

View file

@ -0,0 +1,20 @@
<template>
<div class="exporter">
<div v-if="processing">
<i class="icon-spin4 animate-spin exporter-processing"></i>
<span>{{processingMessage}}</span>
</div>
<button class="btn btn-default" @click="process" v-else>{{exportButtonLabel}}</button>
</div>
</template>
<script src="./exporter.js"></script>
<style lang="scss">
.exporter {
&-processing {
font-size: 1.5em;
margin: 0.25em;
}
}
</style>

View file

@ -14,6 +14,7 @@ import ProgressButton from '../progress_button/progress_button.vue'
import EmojiInput from '../emoji-input/emoji-input.vue' import EmojiInput from '../emoji-input/emoji-input.vue'
import Autosuggest from '../autosuggest/autosuggest.vue' import Autosuggest from '../autosuggest/autosuggest.vue'
import Importer from '../importer/importer.vue' import Importer from '../importer/importer.vue'
import Exporter from '../exporter/exporter.vue'
import withSubscription from '../../hocs/with_subscription/with_subscription' import withSubscription from '../../hocs/with_subscription/with_subscription'
import userSearchApi from '../../services/new_api/user_search.js' import userSearchApi from '../../services/new_api/user_search.js'
@ -41,7 +42,6 @@ const UserSettings = {
hideFollowers: this.$store.state.users.currentUser.hide_followers, hideFollowers: this.$store.state.users.currentUser.hide_followers,
showRole: this.$store.state.users.currentUser.show_role, showRole: this.$store.state.users.currentUser.show_role,
role: this.$store.state.users.currentUser.role, role: this.$store.state.users.currentUser.role,
enableFollowsExport: true,
pickAvatarBtnVisible: true, pickAvatarBtnVisible: true,
bannerUploading: false, bannerUploading: false,
backgroundUploading: false, backgroundUploading: false,
@ -73,7 +73,8 @@ const UserSettings = {
BlockCard, BlockCard,
MuteCard, MuteCard,
ProgressButton, ProgressButton,
Importer Importer,
Exporter
}, },
computed: { computed: {
user () { user () {
@ -250,38 +251,19 @@ const UserSettings = {
} }
}) })
}, },
/* This function takes an Array of Users getFollowsContent () {
* and outputs a file with all the addresses for the user to download return this.$store.state.api.backendInteractor.exportFriends({ id: this.$store.state.users.currentUser.id })
*/
exportPeople (users, filename) {
// Get all the friends addresses
var UserAddresses = users.map(function (user) {
// check is it's a local user
if (user && user.is_local) {
// append the instance address
// eslint-disable-next-line no-undef
user.screen_name += '@' + location.hostname
}
return user.screen_name
}).join('\n')
// Make the user download the file
var fileToDownload = document.createElement('a')
fileToDownload.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(UserAddresses))
fileToDownload.setAttribute('download', filename)
fileToDownload.style.display = 'none'
document.body.appendChild(fileToDownload)
fileToDownload.click()
document.body.removeChild(fileToDownload)
},
exportFollows () {
this.enableFollowsExport = false
this.$store.state.api.backendInteractor
.exportFriends({
id: this.$store.state.users.currentUser.id
})
.then((friendList) => { .then((friendList) => {
this.exportPeople(friendList, 'friends.csv') // Get all the friends addresses
setTimeout(() => { this.enableFollowsExport = true }, 2000) return friendList.map((user) => {
// check is it's a local user
if (user && user.is_local) {
// append the instance address
// eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname
}
return user.screen_name
}).join('\n')
}) })
}, },
confirmDelete () { confirmDelete () {

View file

@ -173,12 +173,9 @@
<p>{{$t('settings.import_followers_from_a_csv_file')}}</p> <p>{{$t('settings.import_followers_from_a_csv_file')}}</p>
<Importer :submitHandler="importFollows" :successMessage="$t('settings.follows_imported')" :errorMessage="$t('settings.follow_import_error')" /> <Importer :submitHandler="importFollows" :successMessage="$t('settings.follows_imported')" :errorMessage="$t('settings.follow_import_error')" />
</div> </div>
<div class="setting-item" v-if="enableFollowsExport"> <div class="setting-item">
<h2>{{$t('settings.follow_export')}}</h2> <h2>{{$t('settings.follow_export')}}</h2>
<button class="btn btn-default" @click="exportFollows">{{$t('settings.follow_export_button')}}</button> <Exporter :getContent="getFollowsContent" filename="friends.csv" :exportButtonLabel="$t('settings.follow_export_button')" />
</div>
<div class="setting-item" v-else>
<h2>{{$t('settings.follow_export_processing')}}</h2>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<h2>{{$t('settings.block_import')}}</h2> <h2>{{$t('settings.block_import')}}</h2>

View file

@ -2,6 +2,10 @@
"chat": { "chat": {
"title": "Chat" "title": "Chat"
}, },
"exporter": {
"export": "Export",
"processing": "Processing, you'll soon be asked to download your file"
},
"features_panel": { "features_panel": {
"chat": "Chat", "chat": "Chat",
"gopher": "Gopher", "gopher": "Gopher",
@ -161,7 +165,6 @@
"filtering_explanation": "All statuses containing these words will be muted, one per line", "filtering_explanation": "All statuses containing these words will be muted, one per line",
"follow_export": "Follow export", "follow_export": "Follow export",
"follow_export_button": "Export your follows to a csv file", "follow_export_button": "Export your follows to a csv file",
"follow_export_processing": "Processing, you'll soon be asked to download your file",
"follow_import": "Follow import", "follow_import": "Follow import",
"follow_import_error": "Error importing followers", "follow_import_error": "Error importing followers",
"follows_imported": "Follows imported! Processing them will take a while.", "follows_imported": "Follows imported! Processing them will take a while.",