environments/review-front-deve-otr6gc/deployments/13419
wvffle 2022-07-21 12:42:58 +00:00 zatwierdzone przez Georg Krause
rodzic bbdb3dcb9d
commit b8f5f5d6ef
5 zmienionych plików z 167 dodań i 182 usunięć

Wyświetl plik

@ -38,6 +38,7 @@
"sass": "1.53.0",
"showdown": "2.1.0",
"text-clipper": "2.2.0",
"transliteration": "^2.3.5",
"vue": "3.2.37",
"vue-gettext": "2.1.12",
"vue-plyr": "7.0.0",

Wyświetl plik

@ -122,16 +122,11 @@ const showUserModal = ref(false)
const showLanguageModal = ref(false)
const showThemeModal = ref(false)
// TODO (wvffle): Use current language this.$language.current
const languageSelection = undefined
// export default {
// watch: {
// languageSelection: function (v) {
// this.$store.dispatch('ui/currentLanguage', v)
// this.$refs.languageModal.closeModal()
// }
// },
// }
const gettext = useGettext()
const languageSelection = ref(gettext.current)
watch(languageSelection, (v) => {
store.dispatch('ui/currentLanguage', v)
})
watch(() => store.state.auth.authenticated, (authenticated) => {
if (authenticated) {

Wyświetl plik

@ -1,3 +1,145 @@
<script setup lang="ts">
import type { Channel, BackendError } from '~/types'
import { slugify } from 'transliteration'
import { reactive, computed, ref, watchEffect, watch } from 'vue'
import { useGettext } from 'vue3-gettext'
import axios from 'axios'
import AttachmentInput from '~/components/common/AttachmentInput.vue'
import TagsSelector from '~/components/library/TagsSelector.vue'
interface Props {
object?: Channel | null
step: number
}
const emit = defineEmits(['category', 'submittable', 'loading', 'errored', 'created', 'updated'])
const props = withDefaults(defineProps<Props>(), {
object: null,
step: 1
})
const { $pgettext } = useGettext()
const newValues = reactive({
name: props.object?.artist?.name ?? '',
username: props.object?.actor.preferred_username ?? '',
tags: props.object?.artist?.tags ?? [],
description: props.object?.artist?.description?.text ?? '',
cover: props.object?.artist?.cover?.uuid ?? null,
content_category: props.object?.artist?.content_category ?? 'podcast',
metadata: { ...(props.object?.metadata ?? {}) }
})
const creating = computed(() => props.object === null)
const categoryChoices = computed(() => [
{
value: 'podcast',
label: $pgettext('*/*/*', 'Podcasts'),
helpText: $pgettext('Content/Channels/Help', 'Host your episodes and keep your community updated.')
},
{
value: 'music',
label: $pgettext('*/*/*', 'Artist discography'),
helpText: $pgettext('Content/Channels/Help', 'Publish music you make as a nice discography of albums and singles.')
}
])
interface ITunesCategory {
value: string
label: string
children: []
}
interface MetadataChoices {
itunes_category?: ITunesCategory[] | null
language: {
value: string
label: string
}[]
}
const metadataChoices = ref({ itunes_category: null } as MetadataChoices)
const itunesSubcategories = computed(() => {
for (const element of metadataChoices.value.itunes_category ?? []) {
if (element.value === newValues.metadata.itunes_category) {
return element.children ?? []
}
}
return []
})
const labels = computed(() => ({
namePlaceholder: $pgettext('Content/Channel/Form.Field.Placeholder', 'Awesome channel name'),
usernamePlaceholder: $pgettext('Content/Channel/Form.Field.Placeholder', 'awesomechannelname')
}))
const submittable = computed(() =>
newValues.content_category === 'podcast'
? newValues.name && newValues.username && newValues.metadata.itunes_category && newValues.metadata.language
: newValues.name && newValues.username
)
watch(() => newValues.name, (name) => {
if (creating.value) {
newValues.username = slugify(name)
}
})
watch(() => newValues.metadata.itunes_category, () => {
newValues.metadata.itunes_subcategory = null
})
const isLoading = ref(false)
const errors = ref([] as string[])
watchEffect(() => emit('category', newValues.content_category))
watchEffect(() => emit('loading', isLoading.value))
watchEffect(() => emit('submittable', submittable.value))
// TODO (wvffle): Add loader / Use Suspense
const fetchMetadataChoices = async () => {
try {
const response = await axios.get('channels/metadata-choices')
metadataChoices.value = response.data
} catch (error) {
errors.value = (error as BackendError).backendErrors
}
}
fetchMetadataChoices()
const submit = async () => {
isLoading.value = true
const payload = {
...newValues,
description: newValues.description
? {
content_type: 'text/markdown',
text: newValues.description
}
: null
}
try {
const request = () => creating.value
? axios.post('channels/', payload)
: axios.patch(`channels/${props.object?.uuid}`, payload)
const response = await request()
emit(creating.value ? 'created' : 'updated', response.data)
} catch (error) {
errors.value = (error as BackendError).backendErrors
emit('errored', errors.value)
}
isLoading.value = false
}
</script>
<template>
<form
class="ui form"
@ -78,8 +220,8 @@
<input
v-model="newValues.username"
type="text"
:required="creating || null"
:disabled="!creating || null"
:required="creating"
:disabled="!creating"
:placeholder="labels.usernamePlaceholder"
>
</div>
@ -182,7 +324,7 @@
id="itunes-category"
v-model="newValues.metadata.itunes_subcategory"
name="itunes-category"
:disabled="!newValues.metadata.itunes_category || null"
:disabled="!newValues.metadata.itunes_category"
class="ui dropdown"
>
<option
@ -241,171 +383,3 @@
</div>
</form>
</template>
<script>
import axios from 'axios'
import AttachmentInput from '~/components/common/AttachmentInput.vue'
import TagsSelector from '~/components/library/TagsSelector.vue'
function slugify (text) {
return text.toString().toLowerCase()
.replace(/\s+/g, '') // Remove spaces
.replace(/[^\w]+/g, '') // Remove all non-word chars
}
export default {
components: {
AttachmentInput,
TagsSelector
},
props: {
object: { type: Object, required: false, default: null },
step: { type: Number, required: false, default: 1 }
},
data () {
const oldValues = {}
if (this.object) {
oldValues.metadata = { ...(this.object.metadata || {}) }
oldValues.name = this.object.artist.name
oldValues.description = this.object.artist.description
oldValues.cover = this.object.artist.cover
oldValues.tags = this.object.artist.tags
oldValues.content_category = this.object.artist.content_category
oldValues.username = this.object.actor.preferred_username
}
return {
isLoading: false,
errors: [],
metadataChoices: null,
newValues: {
name: oldValues.name || '',
username: oldValues.username || '',
tags: oldValues.tags || [],
description: (oldValues.description || {}).text || '',
cover: (oldValues.cover || {}).uuid || null,
content_category: oldValues.content_category || 'podcast',
metadata: oldValues.metadata || {}
}
}
},
computed: {
creating () {
return this.object === null
},
categoryChoices () {
return [
{
value: 'podcast',
label: this.$pgettext('*/*/*', 'Podcasts'),
helpText: this.$pgettext('Content/Channels/Help', 'Host your episodes and keep your community updated.')
},
{
value: 'music',
label: this.$pgettext('*/*/*', 'Artist discography'),
helpText: this.$pgettext('Content/Channels/Help', 'Publish music you make as a nice discography of albums and singles.')
}
]
},
itunesSubcategories () {
for (let index = 0; index < this.metadataChoices.itunes_category.length; index++) {
const element = this.metadataChoices.itunes_category[index]
if (element.value === this.newValues.metadata.itunes_category) {
return element.children || []
}
}
return []
},
labels () {
return {
namePlaceholder: this.$pgettext('Content/Channel/Form.Field.Placeholder', 'Awesome channel name'),
usernamePlaceholder: this.$pgettext('Content/Channel/Form.Field.Placeholder', 'awesomechannelname')
}
},
submittable () {
let v = this.newValues.name && this.newValues.username
if (this.newValues.content_category === 'podcast') {
v = v && this.newValues.metadata.itunes_category && this.newValues.metadata.language
}
return !!v
}
},
watch: {
'newValues.name' (v) {
if (this.creating) {
this.newValues.username = slugify(v)
}
},
'newValues.metadata.itunes_category' (v) {
this.newValues.metadata.itunes_subcategory = null
},
'newValues.content_category': {
handler (v) {
this.$emit('category', v)
},
immediate: true
},
isLoading: {
handler (v) {
this.$emit('loading', v)
},
immediate: true
},
submittable: {
handler (v) {
this.$emit('submittable', v)
},
immediate: true
}
},
created () {
this.fetchMetadataChoices()
},
methods: {
fetchMetadataChoices () {
const self = this
axios.get('channels/metadata-choices').then((response) => {
self.metadataChoices = response.data
}, error => {
self.errors = error.backendErrors
})
},
submit () {
this.isLoading = true
const self = this
const handler = this.creating ? axios.post : axios.patch
const url = this.creating ? 'channels/' : `channels/${this.object.uuid}`
const payload = {
name: this.newValues.name,
username: this.newValues.username,
tags: this.newValues.tags,
content_category: this.newValues.content_category,
cover: this.newValues.cover,
metadata: this.newValues.metadata
}
if (this.newValues.description) {
payload.description = {
content_type: 'text/markdown',
text: this.newValues.description
}
} else {
payload.description = null
}
handler(url, payload).then((response) => {
self.isLoading = false
if (self.creating) {
self.$emit('created', response.data)
} else {
self.$emit('updated', response.data)
}
}, error => {
self.isLoading = false
self.errors = error.backendErrors
self.$emit('errored', self.errors)
})
}
}
}
</script>

Wyświetl plik

@ -113,6 +113,14 @@ export interface Channel {
subscriptions_count: number
downloads_count: number
content_category: ContentCategory
metadata?: {
itunes_category?: unknown
itunes_subcategory?: unknown
language?: string
owner_name: string
owner_email: string
}
}
export type PrivacyLevel = 'everyone' | 'instance' | 'me'

Wyświetl plik

@ -6237,6 +6237,13 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
transliteration@^2.3.5:
version "2.3.5"
resolved "https://registry.yarnpkg.com/transliteration/-/transliteration-2.3.5.tgz#8f92309575f69e4a8a525dab4ff705ebcf961c45"
integrity sha512-HAGI4Lq4Q9dZ3Utu2phaWgtm3vB6PkLUFqWAScg/UW+1eZ/Tg6Exo4oC0/3VUol/w4BlefLhUUSVBr/9/ZGQOw==
dependencies:
yargs "^17.5.1"
ts-jest@28.0.5:
version "28.0.5"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.5.tgz#31776f768fba6dfc8c061d488840ed0c8eeac8b9"
@ -6895,7 +6902,7 @@ yargs-parser@^21.0.0, yargs-parser@^21.0.1:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@^17.3.1:
yargs@^17.3.1, yargs@^17.5.1:
version "17.5.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==