forked from AkkomaGang/akkoma-fe
Merge branch 'betterStorage' into 'develop'
Better storage See merge request pleroma/pleroma-fe!343
This commit is contained in:
commit
cd48268c85
19 changed files with 316 additions and 170 deletions
|
@ -27,6 +27,11 @@ module.exports = {
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
cookieDomainRewrite: 'localhost'
|
cookieDomainRewrite: 'localhost'
|
||||||
},
|
},
|
||||||
|
'/nodeinfo': {
|
||||||
|
target: 'http://localhost:4000/',
|
||||||
|
changeOrigin: true,
|
||||||
|
cookieDomainRewrite: 'localhost'
|
||||||
|
},
|
||||||
'/socket': {
|
'/socket': {
|
||||||
target: 'http://localhost:4000/',
|
target: 'http://localhost:4000/',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
|
16
src/App.js
16
src/App.js
|
@ -36,9 +36,9 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
currentUser () { return this.$store.state.users.currentUser },
|
currentUser () { return this.$store.state.users.currentUser },
|
||||||
background () {
|
background () {
|
||||||
return this.currentUser.background_image || this.$store.state.config.background
|
return this.currentUser.background_image || this.$store.state.instance.background
|
||||||
},
|
},
|
||||||
enableMask () { return this.supportsMask && this.$store.state.config.logoMask },
|
enableMask () { return this.supportsMask && this.$store.state.instance.logoMask },
|
||||||
logoStyle () {
|
logoStyle () {
|
||||||
return {
|
return {
|
||||||
'visibility': this.enableMask ? 'hidden' : 'visible'
|
'visibility': this.enableMask ? 'hidden' : 'visible'
|
||||||
|
@ -46,24 +46,24 @@ export default {
|
||||||
},
|
},
|
||||||
logoMaskStyle () {
|
logoMaskStyle () {
|
||||||
return this.enableMask ? {
|
return this.enableMask ? {
|
||||||
'mask-image': `url(${this.$store.state.config.logo})`
|
'mask-image': `url(${this.$store.state.instance.logo})`
|
||||||
} : {
|
} : {
|
||||||
'background-color': this.enableMask ? '' : 'transparent'
|
'background-color': this.enableMask ? '' : 'transparent'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
logoBgStyle () {
|
logoBgStyle () {
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
'margin': `${this.$store.state.config.logoMargin} 0`
|
'margin': `${this.$store.state.instance.logoMargin} 0`
|
||||||
}, this.enableMask ? {} : {
|
}, this.enableMask ? {} : {
|
||||||
'background-color': this.enableMask ? '' : 'transparent'
|
'background-color': this.enableMask ? '' : 'transparent'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
logo () { return this.$store.state.config.logo },
|
logo () { return this.$store.state.instance.logo },
|
||||||
style () { return { 'background-image': `url(${this.background})` } },
|
style () { return { 'background-image': `url(${this.background})` } },
|
||||||
sitename () { return this.$store.state.config.name },
|
sitename () { return this.$store.state.instance.name },
|
||||||
chat () { return this.$store.state.chat.channel.state === 'joined' },
|
chat () { return this.$store.state.chat.channel.state === 'joined' },
|
||||||
suggestionsEnabled () { return this.$store.state.config.suggestionsEnabled },
|
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
|
||||||
showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel }
|
showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
activatePanel (panelName) {
|
activatePanel (panelName) {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
const FeaturesPanel = {
|
const FeaturesPanel = {
|
||||||
computed: {
|
computed: {
|
||||||
chat: function () {
|
chat: function () {
|
||||||
return this.$store.state.config.chatAvailable && (!this.$store.state.chatDisabled)
|
return this.$store.state.instance.chatAvailable && (!this.$store.state.chatDisabled)
|
||||||
},
|
},
|
||||||
gopher: function () { return this.$store.state.config.gopherAvailable },
|
gopher: function () { return this.$store.state.instance.gopherAvailable },
|
||||||
whoToFollow: function () { return this.$store.state.config.suggestionsEnabled },
|
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
|
||||||
mediaProxy: function () { return this.$store.state.config.mediaProxyAvailable },
|
mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable },
|
||||||
scopeOptions: function () { return this.$store.state.config.scopeOptionsEnabled },
|
scopeOptions: function () { return this.$store.state.instance.scopeOptionsEnabled },
|
||||||
textlimit: function () { return this.$store.state.config.textlimit }
|
textlimit: function () { return this.$store.state.instance.textlimit }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const InstanceSpecificPanel = {
|
const InstanceSpecificPanel = {
|
||||||
computed: {
|
computed: {
|
||||||
instanceSpecificPanelContent () {
|
instanceSpecificPanelContent () {
|
||||||
return this.$store.state.config.instanceSpecificPanelContent
|
return this.$store.state.instance.instanceSpecificPanelContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ const LoginForm = {
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
loggingIn () { return this.$store.state.users.loggingIn },
|
loggingIn () { return this.$store.state.users.loggingIn },
|
||||||
registrationOpen () { return this.$store.state.config.registrationOpen }
|
registrationOpen () { return this.$store.state.instance.registrationOpen }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit () {
|
submit () {
|
||||||
|
|
|
@ -102,7 +102,7 @@ const PostStatusForm = {
|
||||||
name: '',
|
name: '',
|
||||||
utf: utf || '',
|
utf: utf || '',
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
img: utf ? '' : this.$store.state.config.server + image_url,
|
img: utf ? '' : this.$store.state.instance.server + image_url,
|
||||||
highlighted: index === this.highlighted
|
highlighted: index === this.highlighted
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,16 +120,16 @@ const PostStatusForm = {
|
||||||
return this.$store.state.users.users
|
return this.$store.state.users.users
|
||||||
},
|
},
|
||||||
emoji () {
|
emoji () {
|
||||||
return this.$store.state.config.emoji || []
|
return this.$store.state.instance.emoji || []
|
||||||
},
|
},
|
||||||
customEmoji () {
|
customEmoji () {
|
||||||
return this.$store.state.config.customEmoji || []
|
return this.$store.state.instance.customEmoji || []
|
||||||
},
|
},
|
||||||
statusLength () {
|
statusLength () {
|
||||||
return this.newStatus.status.length
|
return this.newStatus.status.length
|
||||||
},
|
},
|
||||||
statusLengthLimit () {
|
statusLengthLimit () {
|
||||||
return this.$store.state.config.textlimit
|
return this.$store.state.instance.textlimit
|
||||||
},
|
},
|
||||||
hasStatusLengthLimit () {
|
hasStatusLengthLimit () {
|
||||||
return this.statusLengthLimit > 0
|
return this.statusLengthLimit > 0
|
||||||
|
@ -141,10 +141,10 @@ const PostStatusForm = {
|
||||||
return this.hasStatusLengthLimit && (this.statusLength > this.statusLengthLimit)
|
return this.hasStatusLengthLimit && (this.statusLength > this.statusLengthLimit)
|
||||||
},
|
},
|
||||||
scopeOptionsEnabled () {
|
scopeOptionsEnabled () {
|
||||||
return this.$store.state.config.scopeOptionsEnabled
|
return this.$store.state.instance.scopeOptionsEnabled
|
||||||
},
|
},
|
||||||
formattingOptionsEnabled () {
|
formattingOptionsEnabled () {
|
||||||
return this.$store.state.config.formattingOptionsEnabled
|
return this.$store.state.instance.formattingOptionsEnabled
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -5,16 +5,16 @@ const registration = {
|
||||||
registering: false
|
registering: false
|
||||||
}),
|
}),
|
||||||
created () {
|
created () {
|
||||||
if ((!this.$store.state.config.registrationOpen && !this.token) || !!this.$store.state.users.currentUser) {
|
if ((!this.$store.state.instance.registrationOpen && !this.token) || !!this.$store.state.users.currentUser) {
|
||||||
this.$router.push('/main/all')
|
this.$router.push('/main/all')
|
||||||
}
|
}
|
||||||
// Seems like this doesn't work at first page open for some reason
|
// Seems like this doesn't work at first page open for some reason
|
||||||
if (this.$store.state.config.registrationOpen && this.token) {
|
if (this.$store.state.instance.registrationOpen && this.token) {
|
||||||
this.$router.push('/registration')
|
this.$router.push('/registration')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
termsofservice () { return this.$store.state.config.tos },
|
termsofservice () { return this.$store.state.instance.tos },
|
||||||
token () { return this.$route.params.token }
|
token () { return this.$route.params.token }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -6,25 +6,27 @@ import { filter, trim } from 'lodash'
|
||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
data () {
|
data () {
|
||||||
const config = this.$store.state.config
|
const user = this.$store.state.config
|
||||||
|
const instance = this.$store.state.instance
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hideAttachmentsLocal: config.hideAttachments,
|
hideAttachmentsLocal: user.hideAttachments,
|
||||||
hideAttachmentsInConvLocal: config.hideAttachmentsInConv,
|
hideAttachmentsInConvLocal: user.hideAttachmentsInConv,
|
||||||
hideNsfwLocal: config.hideNsfw,
|
hideNsfwLocal: user.hideNsfw,
|
||||||
notificationVisibilityLocal: config.notificationVisibility,
|
notificationVisibilityLocal: user.notificationVisibility,
|
||||||
replyVisibilityLocal: config.replyVisibility,
|
replyVisibilityLocal: user.replyVisibility,
|
||||||
loopVideoLocal: config.loopVideo,
|
loopVideoLocal: user.loopVideo,
|
||||||
loopVideoSilentOnlyLocal: config.loopVideoSilentOnly,
|
loopVideoSilentOnlyLocal: user.loopVideoSilentOnly,
|
||||||
muteWordsString: config.muteWords.join('\n'),
|
muteWordsString: user.muteWords.join('\n'),
|
||||||
autoLoadLocal: config.autoLoad,
|
autoLoadLocal: user.autoLoad,
|
||||||
streamingLocal: config.streaming,
|
streamingLocal: user.streaming,
|
||||||
pauseOnUnfocusedLocal: config.pauseOnUnfocused,
|
pauseOnUnfocusedLocal: user.pauseOnUnfocused,
|
||||||
hoverPreviewLocal: config.hoverPreview,
|
hoverPreviewLocal: user.hoverPreview,
|
||||||
collapseMessageWithSubjectLocal: typeof config.collapseMessageWithSubject === 'undefined'
|
collapseMessageWithSubjectLocal: typeof user.collapseMessageWithSubject === 'undefined'
|
||||||
? config.defaultCollapseMessageWithSubject
|
? instance.collapseMessageWithSubject
|
||||||
: config.collapseMessageWithSubject,
|
: user.collapseMessageWithSubject,
|
||||||
stopGifs: config.stopGifs,
|
collapseMessageWithSubjectDefault: this.$t('settings.values.' + instance.collapseMessageWithSubject),
|
||||||
|
stopGifs: user.stopGifs,
|
||||||
loopSilentAvailable:
|
loopSilentAvailable:
|
||||||
// Firefox
|
// Firefox
|
||||||
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
|
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
|
||||||
|
@ -42,6 +44,9 @@ const settings = {
|
||||||
computed: {
|
computed: {
|
||||||
user () {
|
user () {
|
||||||
return this.$store.state.users.currentUser
|
return this.$store.state.users.currentUser
|
||||||
|
},
|
||||||
|
currentSaveStateNotice () {
|
||||||
|
return this.$store.state.interface.settings.currentSaveStateNotice
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="settings panel panel-default">
|
<div class="settings panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
{{$t('settings.settings')}}
|
<div class="title">
|
||||||
|
{{$t('settings.settings')}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition name="fade">
|
||||||
|
<template v-if="currentSaveStateNotice">
|
||||||
|
<div @click.prevent class="alert error" v-if="currentSaveStateNotice.error">
|
||||||
|
{{ $t('settings.saving_err') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div @click.prevent class="alert transparent" v-if="!currentSaveStateNotice.error">
|
||||||
|
{{ $t('settings.saving_ok') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<tab-switcher>
|
<tab-switcher>
|
||||||
|
@ -15,7 +29,9 @@
|
||||||
<ul class="setting-list">
|
<ul class="setting-list">
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="collapseMessageWithSubject" v-model="collapseMessageWithSubjectLocal">
|
<input type="checkbox" id="collapseMessageWithSubject" v-model="collapseMessageWithSubjectLocal">
|
||||||
<label for="collapseMessageWithSubject">{{$t('settings.collapse_subject')}}</label>
|
<label for="collapseMessageWithSubject">
|
||||||
|
{{$t('settings.collapse_subject')}} {{$t('settings.instance_default', { value: collapseMessageWithSubjectDefault })}}
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="streaming" v-model="streamingLocal">
|
<input type="checkbox" id="streaming" v-model="streamingLocal">
|
||||||
|
|
|
@ -32,10 +32,10 @@ const UserSettings = {
|
||||||
return this.$store.state.users.currentUser
|
return this.$store.state.users.currentUser
|
||||||
},
|
},
|
||||||
pleromaBackend () {
|
pleromaBackend () {
|
||||||
return this.$store.state.config.pleromaBackend
|
return this.$store.state.instance.pleromaBackend
|
||||||
},
|
},
|
||||||
scopeOptionsEnabled () {
|
scopeOptionsEnabled () {
|
||||||
return this.$store.state.config.scopeOptionsEnabled
|
return this.$store.state.instance.scopeOptionsEnabled
|
||||||
},
|
},
|
||||||
vis () {
|
vis () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -83,14 +83,14 @@ const WhoToFollowPanel = {
|
||||||
moreUrl: function () {
|
moreUrl: function () {
|
||||||
var host = window.location.hostname
|
var host = window.location.hostname
|
||||||
var user = this.user
|
var user = this.user
|
||||||
var suggestionsWeb = this.$store.state.config.suggestionsWeb
|
var suggestionsWeb = this.$store.state.instance.suggestionsWeb
|
||||||
var url
|
var url
|
||||||
url = suggestionsWeb.replace(/{{host}}/g, encodeURIComponent(host))
|
url = suggestionsWeb.replace(/{{host}}/g, encodeURIComponent(host))
|
||||||
url = url.replace(/{{user}}/g, encodeURIComponent(user))
|
url = url.replace(/{{user}}/g, encodeURIComponent(user))
|
||||||
return url
|
return url
|
||||||
},
|
},
|
||||||
suggestionsEnabled () {
|
suggestionsEnabled () {
|
||||||
return this.$store.state.config.suggestionsEnabled
|
return this.$store.state.instance.suggestionsEnabled
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<img v-bind:src="img1"/> <router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br>
|
<img v-bind:src="img1"/> <router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br>
|
||||||
<img v-bind:src="img2"/> <router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br>
|
<img v-bind:src="img2"/> <router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br>
|
||||||
<img v-bind:src="img3"/> <router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br>
|
<img v-bind:src="img3"/> <router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br>
|
||||||
<img v-bind:src="$store.state.config.logo"> <a v-bind:href="moreUrl" target="_blank">{{$t('who_to_follow.more')}}</a>
|
<img v-bind:src="$store.state.instance.logo"> <a v-bind:href="moreUrl" target="_blank">{{$t('who_to_follow.more')}}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -114,6 +114,7 @@
|
||||||
"import_followers_from_a_csv_file": "Import follows from a csv file",
|
"import_followers_from_a_csv_file": "Import follows from a csv file",
|
||||||
"import_theme": "Load preset",
|
"import_theme": "Load preset",
|
||||||
"inputRadius": "Input fields",
|
"inputRadius": "Input fields",
|
||||||
|
"instance_default: (default": "{value})",
|
||||||
"interfaceLanguage": "Interface language",
|
"interfaceLanguage": "Interface language",
|
||||||
"invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
|
"invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
|
||||||
"limited_availability": "Unavailable in your browser",
|
"limited_availability": "Unavailable in your browser",
|
||||||
|
@ -142,6 +143,8 @@
|
||||||
"reply_visibility_all": "Show all replies",
|
"reply_visibility_all": "Show all replies",
|
||||||
"reply_visibility_following": "Only show replies directed at me or users I'm following",
|
"reply_visibility_following": "Only show replies directed at me or users I'm following",
|
||||||
"reply_visibility_self": "Only show replies directed at me",
|
"reply_visibility_self": "Only show replies directed at me",
|
||||||
|
"saving_err": "Error saving settings",
|
||||||
|
"saving_ok": "Settings saved",
|
||||||
"security_tab": "Security",
|
"security_tab": "Security",
|
||||||
"set_new_avatar": "Set new avatar",
|
"set_new_avatar": "Set new avatar",
|
||||||
"set_new_profile_background": "Set new profile background",
|
"set_new_profile_background": "Set new profile background",
|
||||||
|
@ -153,7 +156,11 @@
|
||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
|
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
|
||||||
"tooltipRadius": "Tooltips/alerts",
|
"tooltipRadius": "Tooltips/alerts",
|
||||||
"user_settings": "User Settings"
|
"user_settings": "User Settings",
|
||||||
|
"values": {
|
||||||
|
"false": "no",
|
||||||
|
"true": "yes"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Collapse",
|
"collapse": "Collapse",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import merge from 'lodash.merge'
|
import merge from 'lodash.merge'
|
||||||
import objectPath from 'object-path'
|
import objectPath from 'object-path'
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
import { throttle, each } from 'lodash'
|
import { each } from 'lodash'
|
||||||
|
|
||||||
let loaded = false
|
let loaded = false
|
||||||
|
|
||||||
|
@ -12,18 +12,18 @@ const defaultReducer = (state, paths) => (
|
||||||
}, {})
|
}, {})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const saveImmedeatelyActions = [
|
||||||
|
'markNotificationsAsSeen',
|
||||||
|
'clearCurrentUser',
|
||||||
|
'setCurrentUser',
|
||||||
|
'setHighlight',
|
||||||
|
'setOption'
|
||||||
|
]
|
||||||
|
|
||||||
const defaultStorage = (() => {
|
const defaultStorage = (() => {
|
||||||
return localforage
|
return localforage
|
||||||
})()
|
})()
|
||||||
|
|
||||||
const defaultSetState = (key, state, storage) => {
|
|
||||||
if (!loaded) {
|
|
||||||
console.log('waiting for old state to be loaded...')
|
|
||||||
} else {
|
|
||||||
return storage.setItem(key, state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function createPersistedState ({
|
export default function createPersistedState ({
|
||||||
key = 'vuex-lz',
|
key = 'vuex-lz',
|
||||||
paths = [],
|
paths = [],
|
||||||
|
@ -31,7 +31,14 @@ export default function createPersistedState ({
|
||||||
let value = storage.getItem(key)
|
let value = storage.getItem(key)
|
||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
setState = throttle(defaultSetState, 60000),
|
setState = (key, state, storage) => {
|
||||||
|
if (!loaded) {
|
||||||
|
console.log('waiting for old state to be loaded...')
|
||||||
|
return Promise.resolve()
|
||||||
|
} else {
|
||||||
|
return storage.setItem(key, state)
|
||||||
|
}
|
||||||
|
},
|
||||||
reducer = defaultReducer,
|
reducer = defaultReducer,
|
||||||
storage = defaultStorage,
|
storage = defaultStorage,
|
||||||
subscriber = store => handler => store.subscribe(handler)
|
subscriber = store => handler => store.subscribe(handler)
|
||||||
|
@ -72,7 +79,20 @@ export default function createPersistedState ({
|
||||||
|
|
||||||
subscriber(store)((mutation, state) => {
|
subscriber(store)((mutation, state) => {
|
||||||
try {
|
try {
|
||||||
setState(key, reducer(state, paths), storage)
|
if (saveImmedeatelyActions.includes(mutation.type)) {
|
||||||
|
setState(key, reducer(state, paths), storage)
|
||||||
|
.then(success => {
|
||||||
|
if (typeof success !== 'undefined') {
|
||||||
|
if (mutation.type === 'setOption') {
|
||||||
|
store.dispatch('settingsSaved', { success })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, error => {
|
||||||
|
if (mutation.type === 'setOption') {
|
||||||
|
store.dispatch('settingsSaved', { error })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Couldn't persist state:")
|
console.log("Couldn't persist state:")
|
||||||
console.log(e)
|
console.log(e)
|
||||||
|
|
194
src/main.js
194
src/main.js
|
@ -14,6 +14,8 @@ import Registration from './components/registration/registration.vue'
|
||||||
import UserSettings from './components/user_settings/user_settings.vue'
|
import UserSettings from './components/user_settings/user_settings.vue'
|
||||||
import FollowRequests from './components/follow_requests/follow_requests.vue'
|
import FollowRequests from './components/follow_requests/follow_requests.vue'
|
||||||
|
|
||||||
|
import interfaceModule from './modules/interface.js'
|
||||||
|
import instanceModule from './modules/instance.js'
|
||||||
import statusesModule from './modules/statuses.js'
|
import statusesModule from './modules/statuses.js'
|
||||||
import usersModule from './modules/users.js'
|
import usersModule from './modules/users.js'
|
||||||
import apiModule from './modules/api.js'
|
import apiModule from './modules/api.js'
|
||||||
|
@ -45,23 +47,7 @@ Vue.use(VueChatScroll)
|
||||||
|
|
||||||
const persistedStateOptions = {
|
const persistedStateOptions = {
|
||||||
paths: [
|
paths: [
|
||||||
'config.collapseMessageWithSubject',
|
'config',
|
||||||
'config.hideAttachments',
|
|
||||||
'config.hideAttachmentsInConv',
|
|
||||||
'config.hideNsfw',
|
|
||||||
'config.replyVisibility',
|
|
||||||
'config.notificationVisibility',
|
|
||||||
'config.autoLoad',
|
|
||||||
'config.hoverPreview',
|
|
||||||
'config.streaming',
|
|
||||||
'config.muteWords',
|
|
||||||
'config.customTheme',
|
|
||||||
'config.highlight',
|
|
||||||
'config.loopVideo',
|
|
||||||
'config.loopVideoSilentOnly',
|
|
||||||
'config.pauseOnUnfocused',
|
|
||||||
'config.stopGifs',
|
|
||||||
'config.interfaceLanguage',
|
|
||||||
'users.lastLoginName',
|
'users.lastLoginName',
|
||||||
'statuses.notifications.maxSavedId'
|
'statuses.notifications.maxSavedId'
|
||||||
]
|
]
|
||||||
|
@ -69,6 +55,8 @@ const persistedStateOptions = {
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
modules: {
|
modules: {
|
||||||
|
interface: interfaceModule,
|
||||||
|
instance: instanceModule,
|
||||||
statuses: statusesModule,
|
statuses: statusesModule,
|
||||||
users: usersModule,
|
users: usersModule,
|
||||||
api: apiModule,
|
api: apiModule,
|
||||||
|
@ -92,92 +80,100 @@ window.fetch('/api/statusnet/config.json')
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const {name, closed: registrationClosed, textlimit, server} = data.site
|
const {name, closed: registrationClosed, textlimit, server} = data.site
|
||||||
|
|
||||||
store.dispatch('setOption', { name: 'name', value: name })
|
store.dispatch('setInstanceOption', { name: 'name', value: name })
|
||||||
store.dispatch('setOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
|
store.dispatch('setInstanceOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
|
||||||
store.dispatch('setOption', { name: 'textlimit', value: parseInt(textlimit) })
|
store.dispatch('setInstanceOption', { name: 'textlimit', value: parseInt(textlimit) })
|
||||||
store.dispatch('setOption', { name: 'server', value: server })
|
store.dispatch('setInstanceOption', { name: 'server', value: server })
|
||||||
|
|
||||||
var apiConfig = data.site.pleromafe
|
var apiConfig = data.site.pleromafe
|
||||||
|
|
||||||
window.fetch('/static/config.json')
|
window.fetch('/static/config.json')
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.catch((err) => {
|
||||||
var staticConfig = data
|
console.warn('Failed to load static/config.json, continuing without it.')
|
||||||
// This takes static config and overrides properties that are present in apiConfig
|
console.warn(err)
|
||||||
var config = Object.assign({}, staticConfig, apiConfig)
|
return {}
|
||||||
|
})
|
||||||
|
.then((staticConfig) => {
|
||||||
|
// This takes static config and overrides properties that are present in apiConfig
|
||||||
|
var config = Object.assign({}, staticConfig, apiConfig)
|
||||||
|
|
||||||
var theme = (config.theme)
|
var theme = (config.theme)
|
||||||
var background = (config.background)
|
var background = (config.background)
|
||||||
var logo = (config.logo)
|
var logo = (config.logo)
|
||||||
var logoMask = (typeof config.logoMask === 'undefined' ? true : config.logoMask)
|
var logoMask = (typeof config.logoMask === 'undefined' ? true : config.logoMask)
|
||||||
var logoMargin = (typeof config.logoMargin === 'undefined' ? 0 : config.logoMargin)
|
var logoMargin = (typeof config.logoMargin === 'undefined' ? 0 : config.logoMargin)
|
||||||
var redirectRootNoLogin = (config.redirectRootNoLogin)
|
var redirectRootNoLogin = (config.redirectRootNoLogin)
|
||||||
var redirectRootLogin = (config.redirectRootLogin)
|
var redirectRootLogin = (config.redirectRootLogin)
|
||||||
var chatDisabled = (config.chatDisabled)
|
var chatDisabled = (config.chatDisabled)
|
||||||
var showInstanceSpecificPanel = (config.showInstanceSpecificPanel)
|
var showInstanceSpecificPanel = (config.showInstanceSpecificPanel)
|
||||||
var scopeOptionsEnabled = (config.scopeOptionsEnabled)
|
var scopeOptionsEnabled = (config.scopeOptionsEnabled)
|
||||||
var formattingOptionsEnabled = (config.formattingOptionsEnabled)
|
var formattingOptionsEnabled = (config.formattingOptionsEnabled)
|
||||||
var defaultCollapseMessageWithSubject = (config.collapseMessageWithSubject)
|
var collapseMessageWithSubject = (config.collapseMessageWithSubject)
|
||||||
|
|
||||||
store.dispatch('setOption', { name: 'theme', value: theme })
|
store.dispatch('setInstanceOption', { name: 'theme', value: theme })
|
||||||
store.dispatch('setOption', { name: 'background', value: background })
|
store.dispatch('setInstanceOption', { name: 'background', value: background })
|
||||||
store.dispatch('setOption', { name: 'logo', value: logo })
|
store.dispatch('setInstanceOption', { name: 'logo', value: logo })
|
||||||
store.dispatch('setOption', { name: 'logoMask', value: logoMask })
|
store.dispatch('setInstanceOption', { name: 'logoMask', value: logoMask })
|
||||||
store.dispatch('setOption', { name: 'logoMargin', value: logoMargin })
|
store.dispatch('setInstanceOption', { name: 'logoMargin', value: logoMargin })
|
||||||
store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
|
store.dispatch('setInstanceOption', { name: 'redirectRootNoLogin', value: redirectRootNoLogin })
|
||||||
store.dispatch('setOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
|
store.dispatch('setInstanceOption', { name: 'redirectRootLogin', value: redirectRootLogin })
|
||||||
store.dispatch('setOption', { name: 'formattingOptionsEnabled', value: formattingOptionsEnabled })
|
store.dispatch('setInstanceOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
|
||||||
store.dispatch('setOption', { name: 'defaultCollapseMessageWithSubject', value: defaultCollapseMessageWithSubject })
|
store.dispatch('setInstanceOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
|
||||||
if (chatDisabled) {
|
store.dispatch('setInstanceOption', { name: 'formattingOptionsEnabled', value: formattingOptionsEnabled })
|
||||||
store.dispatch('disableChat')
|
store.dispatch('setInstanceOption', { name: 'collapseMessageWithSubject', value: collapseMessageWithSubject })
|
||||||
}
|
if (chatDisabled) {
|
||||||
|
store.dispatch('disableChat')
|
||||||
const routes = [
|
|
||||||
{ name: 'root',
|
|
||||||
path: '/',
|
|
||||||
redirect: to => {
|
|
||||||
return (store.state.users.currentUser ? redirectRootLogin : redirectRootNoLogin) || '/main/all'
|
|
||||||
}},
|
|
||||||
{ path: '/main/all', component: PublicAndExternalTimeline },
|
|
||||||
{ path: '/main/public', component: PublicTimeline },
|
|
||||||
{ path: '/main/friends', component: FriendsTimeline },
|
|
||||||
{ path: '/tag/:tag', component: TagTimeline },
|
|
||||||
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
|
||||||
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
|
|
||||||
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
|
|
||||||
{ name: 'settings', path: '/settings', component: Settings },
|
|
||||||
{ name: 'registration', path: '/registration', component: Registration },
|
|
||||||
{ name: 'registration', path: '/registration/:token', component: Registration },
|
|
||||||
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
|
|
||||||
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
|
|
||||||
]
|
|
||||||
|
|
||||||
const router = new VueRouter({
|
|
||||||
mode: 'history',
|
|
||||||
routes,
|
|
||||||
scrollBehavior: (to, from, savedPosition) => {
|
|
||||||
if (to.matched.some(m => m.meta.dontScroll)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return savedPosition || { x: 0, y: 0 }
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
const routes = [
|
||||||
new Vue({
|
{ name: 'root',
|
||||||
router,
|
path: '/',
|
||||||
store,
|
redirect: to => {
|
||||||
i18n,
|
return (store.state.users.currentUser
|
||||||
el: '#app',
|
? store.state.instance.redirectRootLogin
|
||||||
render: h => h(App)
|
: store.state.instance.redirectRootNoLogin) || '/main/all'
|
||||||
|
}},
|
||||||
|
{ path: '/main/all', component: PublicAndExternalTimeline },
|
||||||
|
{ path: '/main/public', component: PublicTimeline },
|
||||||
|
{ path: '/main/friends', component: FriendsTimeline },
|
||||||
|
{ path: '/tag/:tag', component: TagTimeline },
|
||||||
|
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
||||||
|
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
|
||||||
|
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
|
||||||
|
{ name: 'settings', path: '/settings', component: Settings },
|
||||||
|
{ name: 'registration', path: '/registration', component: Registration },
|
||||||
|
{ name: 'registration', path: '/registration/:token', component: Registration },
|
||||||
|
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
|
||||||
|
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: 'history',
|
||||||
|
routes,
|
||||||
|
scrollBehavior: (to, from, savedPosition) => {
|
||||||
|
if (to.matched.some(m => m.meta.dontScroll)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return savedPosition || { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/* eslint-disable no-new */
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
i18n,
|
||||||
|
el: '#app',
|
||||||
|
render: h => h(App)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
window.fetch('/static/terms-of-service.html')
|
window.fetch('/static/terms-of-service.html')
|
||||||
.then((res) => res.text())
|
.then((res) => res.text())
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
store.dispatch('setOption', { name: 'tos', value: html })
|
store.dispatch('setInstanceOption', { name: 'tos', value: html })
|
||||||
})
|
})
|
||||||
|
|
||||||
window.fetch('/api/pleroma/emoji.json')
|
window.fetch('/api/pleroma/emoji.json')
|
||||||
|
@ -188,11 +184,11 @@ window.fetch('/api/pleroma/emoji.json')
|
||||||
const emoji = Object.keys(values).map((key) => {
|
const emoji = Object.keys(values).map((key) => {
|
||||||
return { shortcode: key, image_url: values[key] }
|
return { shortcode: key, image_url: values[key] }
|
||||||
})
|
})
|
||||||
store.dispatch('setOption', { name: 'customEmoji', value: emoji })
|
store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji })
|
||||||
store.dispatch('setOption', { name: 'pleromaBackend', value: true })
|
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: true })
|
||||||
},
|
},
|
||||||
(failure) => {
|
(failure) => {
|
||||||
store.dispatch('setOption', { name: 'pleromaBackend', value: false })
|
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: false })
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
(error) => console.log(error)
|
(error) => console.log(error)
|
||||||
|
@ -204,24 +200,24 @@ window.fetch('/static/emoji.json')
|
||||||
const emoji = Object.keys(values).map((key) => {
|
const emoji = Object.keys(values).map((key) => {
|
||||||
return { shortcode: key, image_url: false, 'utf': values[key] }
|
return { shortcode: key, image_url: false, 'utf': values[key] }
|
||||||
})
|
})
|
||||||
store.dispatch('setOption', { name: 'emoji', value: emoji })
|
store.dispatch('setInstanceOption', { name: 'emoji', value: emoji })
|
||||||
})
|
})
|
||||||
|
|
||||||
window.fetch('/instance/panel.html')
|
window.fetch('/instance/panel.html')
|
||||||
.then((res) => res.text())
|
.then((res) => res.text())
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
store.dispatch('setOption', { name: 'instanceSpecificPanelContent', value: html })
|
store.dispatch('setInstanceOption', { name: 'instanceSpecificPanelContent', value: html })
|
||||||
})
|
})
|
||||||
|
|
||||||
window.fetch('/nodeinfo/2.0.json')
|
window.fetch('/nodeinfo/2.0.json')
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const metadata = data.metadata
|
const metadata = data.metadata
|
||||||
store.dispatch('setOption', { name: 'mediaProxyAvailable', value: data.metadata.mediaProxy })
|
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: data.metadata.mediaProxy })
|
||||||
store.dispatch('setOption', { name: 'chatAvailable', value: data.metadata.chat })
|
store.dispatch('setInstanceOption', { name: 'chatAvailable', value: data.metadata.chat })
|
||||||
store.dispatch('setOption', { name: 'gopherAvailable', value: data.metadata.gopher })
|
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: data.metadata.gopher })
|
||||||
|
|
||||||
const suggestions = metadata.suggestions
|
const suggestions = metadata.suggestions
|
||||||
store.dispatch('setOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
|
store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
|
||||||
store.dispatch('setOption', { name: 'suggestionsWeb', value: suggestions.web })
|
store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web })
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,6 @@ import StyleSetter from '../services/style_setter/style_setter.js'
|
||||||
const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
name: 'Pleroma FE',
|
|
||||||
colors: {},
|
colors: {},
|
||||||
collapseMessageWithSubject: false,
|
collapseMessageWithSubject: false,
|
||||||
hideAttachments: false,
|
hideAttachments: false,
|
||||||
|
@ -45,18 +44,12 @@ const config = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setPageTitle ({state}, option = '') {
|
|
||||||
document.title = `${option} ${state.name}`
|
|
||||||
},
|
|
||||||
setHighlight ({ commit, dispatch }, { user, color, type }) {
|
setHighlight ({ commit, dispatch }, { user, color, type }) {
|
||||||
commit('setHighlight', {user, color, type})
|
commit('setHighlight', {user, color, type})
|
||||||
},
|
},
|
||||||
setOption ({ commit, dispatch }, { name, value }) {
|
setOption ({ commit, dispatch }, { name, value }) {
|
||||||
commit('setOption', {name, value})
|
commit('setOption', {name, value})
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'name':
|
|
||||||
dispatch('setPageTitle')
|
|
||||||
break
|
|
||||||
case 'theme':
|
case 'theme':
|
||||||
StyleSetter.setPreset(value, commit)
|
StyleSetter.setPreset(value, commit)
|
||||||
break
|
break
|
||||||
|
|
63
src/modules/instance.js
Normal file
63
src/modules/instance.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { set } from 'vue'
|
||||||
|
import StyleSetter from '../services/style_setter/style_setter.js'
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
// Stuff from static/config.json and apiConfig
|
||||||
|
name: 'Pleroma FE',
|
||||||
|
registrationOpen: true,
|
||||||
|
textlimit: 5000,
|
||||||
|
server: 'http://localhost:4040/',
|
||||||
|
theme: 'pleroma-dark',
|
||||||
|
background: '/static/aurora_borealis.jpg',
|
||||||
|
logo: '/static/logo.png',
|
||||||
|
logoMask: true,
|
||||||
|
logoMargin: '.2em',
|
||||||
|
redirectRootNoLogin: '/main/all',
|
||||||
|
redirectRootLogin: '/main/friends',
|
||||||
|
showInstanceSpecificPanel: false,
|
||||||
|
scopeOptionsEnabled: true,
|
||||||
|
formattingOptionsEnabled: false,
|
||||||
|
collapseMessageWithSubject: false,
|
||||||
|
disableChat: false,
|
||||||
|
|
||||||
|
// Nasty stuff
|
||||||
|
pleromaBackend: true,
|
||||||
|
emoji: [],
|
||||||
|
customEmoji: [],
|
||||||
|
|
||||||
|
// Feature-set, apparently, not everything here is reported...
|
||||||
|
mediaProxyAvailable: false,
|
||||||
|
chatAvailable: false,
|
||||||
|
gopherAvailable: false,
|
||||||
|
suggestionsEnabled: false,
|
||||||
|
suggestionsWeb: '',
|
||||||
|
|
||||||
|
// Html stuff
|
||||||
|
instanceSpecificPanelContent: '',
|
||||||
|
tos: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = {
|
||||||
|
state: defaultState,
|
||||||
|
mutations: {
|
||||||
|
setInstanceOption (state, { name, value }) {
|
||||||
|
if (typeof value !== 'undefined') {
|
||||||
|
set(state, name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setInstanceOption ({ commit, dispatch }, { name, value }) {
|
||||||
|
commit('setInstanceOption', {name, value})
|
||||||
|
switch (name) {
|
||||||
|
case 'name':
|
||||||
|
dispatch('setPageTitle')
|
||||||
|
break
|
||||||
|
case 'theme':
|
||||||
|
StyleSetter.setPreset(value, commit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default instance
|
36
src/modules/interface.js
Normal file
36
src/modules/interface.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { set, delete as del } from 'vue'
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
settings: {
|
||||||
|
currentSaveStateNotice: null,
|
||||||
|
noticeClearTimeout: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const interfaceMod = {
|
||||||
|
state: defaultState,
|
||||||
|
mutations: {
|
||||||
|
settingsSaved (state, { success, error }) {
|
||||||
|
if (success) {
|
||||||
|
if (state.noticeClearTimeout) {
|
||||||
|
clearTimeout(state.noticeClearTimeout)
|
||||||
|
}
|
||||||
|
set(state.settings, 'currentSaveStateNotice', { error: false, data: success })
|
||||||
|
set(state.settings, 'noticeClearTimeout',
|
||||||
|
setTimeout(() => del(state.settings, 'currentSaveStateNotice'), 2000))
|
||||||
|
} else {
|
||||||
|
set(state.settings, 'currentSaveStateNotice', { error: true, errorData: error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setPageTitle ({ rootState }, option = '') {
|
||||||
|
document.title = `${option} ${rootState.instance.name}`
|
||||||
|
},
|
||||||
|
settingsSaved ({ commit, dispatch }, { success, error }) {
|
||||||
|
commit('settingsSaved', { success, error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default interfaceMod
|
|
@ -133,8 +133,6 @@ const updateBanner = ({credentials, params}) => {
|
||||||
const updateProfile = ({credentials, params}) => {
|
const updateProfile = ({credentials, params}) => {
|
||||||
let url = PROFILE_UPDATE_URL
|
let url = PROFILE_UPDATE_URL
|
||||||
|
|
||||||
console.log(params)
|
|
||||||
|
|
||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
|
|
||||||
each(params, (value, key) => {
|
each(params, (value, key) => {
|
||||||
|
@ -335,7 +333,14 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
|
||||||
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
|
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
|
||||||
url += `?${queryString}`
|
url += `?${queryString}`
|
||||||
|
|
||||||
return fetch(url, { headers: authHeaders(credentials) }).then((data) => data.json())
|
return fetch(url, { headers: authHeaders(credentials) })
|
||||||
|
.then((data) => {
|
||||||
|
if (data.ok) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
throw new Error('Error fetching timeline')
|
||||||
|
})
|
||||||
|
.then((data) => data.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
const verifyCredentials = (user) => {
|
const verifyCredentials = (user) => {
|
||||||
|
|
Loading…
Reference in a new issue