mirror of
https://codeberg.org/dragongoose/safetwitch.git
synced 2024-09-06 16:42:33 +00:00
Add proper error handling and loading screen
This commit is contained in:
parent
9104e62779
commit
d27ef3560c
5 changed files with 100 additions and 86 deletions
|
@ -1,22 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {}
|
||||||
props: {
|
|
||||||
errMessage: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
{
|
|
||||||
;('Error')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props) {
|
|
||||||
return {
|
|
||||||
errorMessage: props.errMessage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -31,10 +14,5 @@ export default {
|
||||||
<p class="text-xl">
|
<p class="text-xl">
|
||||||
the server was encountered an error while retriving the data, and now we're here :3
|
the server was encountered an error while retriving the data, and now we're here :3
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="mt-5">
|
|
||||||
<p class="text-xl">please contact the administrator with this code</p>
|
|
||||||
<p class="text-xl">error identifier: {{ errorMessage.code }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
8
src/components/LoadingScreen.vue
Normal file
8
src/components/LoadingScreen.vue
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex mx-auto justify-center bg-ctp-crust rounded-lg w-2/3 p-2 text-white">
|
||||||
|
<div class="flex space-x-3">
|
||||||
|
<h1 class="text-4xl font-bold">Searching...</h1>
|
||||||
|
<v-icon name="fa-circle-notch" class="animate-spin w-10 h-10"></v-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -1,22 +1,35 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { useRoute } from 'vue-router'
|
import { ref, type Ref } from 'vue'
|
||||||
import StreamPreviewVue from '@/components/StreamPreview.vue'
|
import StreamPreviewVue from '@/components/StreamPreview.vue'
|
||||||
|
import ErrorMessage from '@/components/ErrorMessage.vue'
|
||||||
|
import LoadingScreen from '@/components/LoadingScreen.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async setup() {
|
async setup() {
|
||||||
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
||||||
|
const data: Ref<any | undefined> = ref()
|
||||||
|
const frontend_url = protocol + import.meta.env.VITE_INSTANCE_DOMAIN
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const game = route.params.game
|
|
||||||
const res = await fetch(`${protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/discover/${game}`)
|
|
||||||
const data = await res.json()
|
|
||||||
let frontend_url = protocol + import.meta.env.VITE_INSTANCE_DOMAIN
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
frontend_url
|
frontend_url
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async mounted() {
|
||||||
|
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
||||||
|
const game: string = this.$route.params.game.toString()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/discover/${game}`)
|
||||||
|
if (!res.ok) {
|
||||||
|
return this.data = { status: 'error' }
|
||||||
|
}
|
||||||
|
this.data = await res.json()
|
||||||
|
} catch (err) {
|
||||||
|
this.data = { status: 'error' }
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
abbreviate(text: number) {
|
abbreviate(text: number) {
|
||||||
return Intl.NumberFormat('en-US', {
|
return Intl.NumberFormat('en-US', {
|
||||||
|
@ -27,13 +40,18 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
StreamPreviewVue
|
StreamPreviewVue,
|
||||||
|
ErrorMessage,
|
||||||
|
LoadingScreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col max-w-5xl mx-auto">
|
<loading-screen v-if="!data"></loading-screen>
|
||||||
|
<error-message v-else-if="data.status === 'error' || !data"></error-message>
|
||||||
|
|
||||||
|
<div v-else class="flex flex-col max-w-5xl mx-auto">
|
||||||
<div class="flex space-x-4 p-3">
|
<div class="flex space-x-4 p-3">
|
||||||
<img :src="data.cover" class="self-start rounded-md" />
|
<img :src="data.cover" class="self-start rounded-md" />
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, type Ref } from 'vue'
|
import { ref, type Ref } from 'vue'
|
||||||
import StreamPreviewVue from '@/components/StreamPreview.vue'
|
import StreamPreviewVue from '@/components/StreamPreview.vue'
|
||||||
|
import ErrorMessage from '@/components/ErrorMessage.vue'
|
||||||
|
import LoadingScreen from '@/components/LoadingScreen.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async setup() {
|
async setup() {
|
||||||
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
||||||
|
|
||||||
const res = await fetch(`${protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/discover`)
|
let data: Ref<any | undefined> = ref()
|
||||||
let data: Ref<any[] | undefined> = ref()
|
|
||||||
let frontend_url = protocol + import.meta.env.VITE_INSTANCE_DOMAIN
|
let frontend_url = protocol + import.meta.env.VITE_INSTANCE_DOMAIN
|
||||||
data.value = await res.json()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
|
@ -29,8 +30,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
filterSearches(toFilter: string) {
|
filterSearches(toFilter: string) {
|
||||||
const categories = this.$refs.categoryItem
|
const categories: HTMLCollectionOf<Element> = this.$refs.categoryItem as HTMLCollectionOf<Element>
|
||||||
const wantedTags = toFilter.split(',').filter((v) => v.toLowerCase())
|
const wantedTags: string[] = toFilter.split(',').filter((v) => v.toLowerCase())
|
||||||
|
|
||||||
for (let category of categories as any) {
|
for (let category of categories as any) {
|
||||||
let tagElements = category.getElementsByTagName('span')
|
let tagElements = category.getElementsByTagName('span')
|
||||||
|
@ -67,6 +68,9 @@ export default {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`${this.protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/discover/?cursor=${cursor}`
|
`${this.protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/discover/?cursor=${cursor}`
|
||||||
)
|
)
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('Failed to fetch data')
|
||||||
|
}
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
|
|
||||||
for (let category of data) {
|
for (let category of data) {
|
||||||
|
@ -76,7 +80,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.getNextCategory()
|
this.getNextCategory()
|
||||||
|
|
||||||
let following = localStorage.getItem('following')
|
let following = localStorage.getItem('following')
|
||||||
|
@ -85,15 +89,33 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.following = []
|
this.following = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${this.protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/discover`)
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('Failed to fetch data')
|
||||||
|
}
|
||||||
|
this.data = await res.json()
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
this.data = { status: 'error' }
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
StreamPreviewVue
|
StreamPreviewVue,
|
||||||
|
ErrorMessage,
|
||||||
|
LoadingScreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="max-w-5xl mx-auto">
|
|
||||||
|
<loading-screen v-if="!data"></loading-screen>
|
||||||
|
<error-message v-else-if="data.status === 'error'"></error-message>
|
||||||
|
|
||||||
|
<div v-else class="max-w-5xl mx-auto">
|
||||||
<div v-if="following.length > 0" class="p-2 text-white">
|
<div v-if="following.length > 0" class="p-2 text-white">
|
||||||
<h1 class="font-bold text-5xl">Following</h1>
|
<h1 class="font-bold text-5xl">Following</h1>
|
||||||
<p class="text-xl">Streamers you follow</p>
|
<p class="text-xl">Streamers you follow</p>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import VideoPlayer from '@/components/VideoPlayer.vue'
|
||||||
import TwitchChat from '@/components/TwitchChat.vue'
|
import TwitchChat from '@/components/TwitchChat.vue'
|
||||||
import ErrorMessage from '@/components/ErrorMessage.vue'
|
import ErrorMessage from '@/components/ErrorMessage.vue'
|
||||||
import FollowButton from '@/components/FollowButton.vue'
|
import FollowButton from '@/components/FollowButton.vue'
|
||||||
|
import LoadingScreen from '@/components/LoadingScreen.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async setup() {
|
async setup() {
|
||||||
|
@ -13,36 +14,20 @@ export default {
|
||||||
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
const protocol = import.meta.env.VITE_HTTPS === 'true' ? 'https://' : 'http://'
|
||||||
|
|
||||||
const getUser = async () => {
|
const getUser = async () => {
|
||||||
|
try {
|
||||||
const res = await fetch(`${protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/users/${username}`)
|
const res = await fetch(`${protocol}${import.meta.env.VITE_BACKEND_DOMAIN}/api/users/${username}`)
|
||||||
|
|
||||||
if (res.status !== 200) {
|
|
||||||
const data = await res.json()
|
|
||||||
|
|
||||||
if (!data.code) {
|
|
||||||
return {
|
|
||||||
status: 'error',
|
|
||||||
code: 'error'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
return data
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
return {
|
||||||
|
status: 'error',
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = ref()
|
const data = ref()
|
||||||
onMounted(async () => {
|
const videoOptions = {
|
||||||
const fetchedUser = await getUser()
|
|
||||||
data.value = fetchedUser
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
videoOptions: {
|
|
||||||
autoplay: true,
|
autoplay: true,
|
||||||
controls: true,
|
controls: true,
|
||||||
sources: [
|
sources: [
|
||||||
|
@ -53,13 +38,23 @@ export default {
|
||||||
],
|
],
|
||||||
fluid: true
|
fluid: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
videoOptions,
|
||||||
|
getUser
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
VideoPlayer,
|
VideoPlayer,
|
||||||
TwitchChat,
|
TwitchChat,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
FollowButton
|
FollowButton,
|
||||||
|
LoadingScreen
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
const fetchedUser = await this.getUser()
|
||||||
|
this.data = fetchedUser
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
truncate(value: string, length: number) {
|
truncate(value: string, length: number) {
|
||||||
|
@ -73,19 +68,12 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
v-if="!data"
|
|
||||||
id="loadingDiv"
|
|
||||||
class="flex mx-auto justify-center bg-ctp-crust rounded-lg w-2/3 p-2 text-white"
|
|
||||||
>
|
|
||||||
<div class="flex space-x-3">
|
|
||||||
<h1 class="text-4xl font-bold">Searching...</h1>
|
|
||||||
<v-icon name="fa-circle-notch" class="animate-spin w-10 h-10"></v-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<error-message v-else-if="data.status === 'error'" :errMessage="data"></error-message>
|
<template>
|
||||||
|
|
||||||
|
<loading-screen v-if="!data"></loading-screen>
|
||||||
|
|
||||||
|
<error-message v-else-if="data.status === 'error'"></error-message>
|
||||||
|
|
||||||
<div v-else class="w-full justify-center inline-flex space-x-4 p-4">
|
<div v-else class="w-full justify-center inline-flex space-x-4 p-4">
|
||||||
<div class="flex bg-ctp-crust flex-col p-6 rounded-lg max-w-prose min-w-[65ch] text-white">
|
<div class="flex bg-ctp-crust flex-col p-6 rounded-lg max-w-prose min-w-[65ch] text-white">
|
||||||
|
|
Loading…
Reference in a new issue