Browse Source

Merge pull request #9579 from nocodb/nc-product-feed-refactor

fix: product feed fixes
pull/9580/head
navi 2 months ago committed by GitHub
parent
commit
97a39f3ef7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 48
      packages/nc-gui/components/dashboard/Sidebar/Feed.vue
  2. 9
      packages/nc-gui/components/feed/Error.vue
  3. 8
      packages/nc-gui/components/feed/Recents/index.vue
  4. 39
      packages/nc-gui/components/feed/Twitter.vue
  5. 47
      packages/nc-gui/composables/useProductFeed.ts

48
packages/nc-gui/components/dashboard/Sidebar/Feed.vue

@ -1,55 +1,11 @@
<script setup lang="ts">
import dayjs from 'dayjs'
const workspaceStore = useWorkspace()
const { navigateToFeed } = workspaceStore
const { isFeedPageOpened } = storeToRefs(workspaceStore)
const { appInfo } = useGlobal()
const { loadFeed, socialFeed } = useProductFeed()
const isNewFeedAvailable = ref(false)
const checkNewFeed = async () => {
try {
await loadFeed({ type: 'all', loadMore: false })
if (!socialFeed.value.length) return
const [latestFeed] = socialFeed.value
const lastFeedTime = localStorage.getItem('lastFeedPublishedTime')
const lastFeed = dayjs(lastFeedTime)
if (!lastFeed.isValid() || dayjs(latestFeed['Published Time']).isAfter(lastFeed)) {
isNewFeedAvailable.value = true
localStorage.setItem('lastFeedPublishedTime', latestFeed['Published Time'])
}
} catch (error) {
console.error('Error while checking new feed', error)
}
}
const intervalId = ref()
const checkFeedWithInterval = async () => {
await checkNewFeed()
intervalId.value = setTimeout(checkFeedWithInterval, 3 * 60 * 60 * 1000)
}
onMounted(() => {
if (appInfo.value.feedEnabled) {
checkFeedWithInterval()
}
})
onUnmounted(() => {
if (intervalId.value) {
clearTimeout(intervalId.value)
intervalId.value = null
}
})
const { isNewFeedAvailable } = useProductFeed()
const gotoFeed = () => navigateToFeed()
</script>
@ -60,7 +16,7 @@ const gotoFeed = () => navigateToFeed()
type="text"
full-width
size="xsmall"
class="n!xs:hidden my-0.5 !h-7 w-full !rounded-md !font-normal !px-3"
class="n!xs:hidden my-0.5 w-full !h-7 !rounded-md !font-normal !pl-4.5 !pr-5"
data-testid="nc-sidebar-product-feed"
:centered="false"
:class="{

9
packages/nc-gui/components/feed/Error.vue

@ -1,11 +1,18 @@
<script setup lang="ts">
const props = defineProps<{
page: 'all' | 'youtube' | 'github'
page: 'all' | 'youtube' | 'github' | 'twitter'
}>()
const emits = defineEmits(['reload'])
const { loadFeed, socialFeed, youtubeFeed, githubFeed } = useProductFeed()
const triggerReload = async () => {
if (props.page === 'twitter') {
emits('reload')
return
}
const data = (await loadFeed({
type: props.page,
loadMore: false,

8
packages/nc-gui/components/feed/Recents/index.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
const { socialFeed, loadFeed, isErrorOccurred } = useProductFeed()
const { socialFeed, loadFeed, isErrorOccurred, isNewFeedAvailable } = useProductFeed()
const scrollContainer = ref<HTMLElement>()
@ -14,6 +14,12 @@ const { isLoading } = useInfiniteScroll(
},
{ distance: 1, interval: 2000 },
)
onMounted(() => {
isNewFeedAvailable.value = false
const [latestFeed] = socialFeed.value
if (latestFeed) localStorage.setItem('lastFeedPublishedTime', latestFeed['Published Time'])
})
</script>
<template>

39
packages/nc-gui/components/feed/Twitter.vue

@ -1,17 +1,33 @@
<script setup lang="ts">
const isLoaded = ref(false)
const scriptTag = ref()
const timelineStatus = reactive({
isLoaded: false,
isError: false,
})
const handleIframeLoad = () => {
setTimeout(() => {
isLoaded.value = true
timelineStatus.isLoaded = true
}, 2000)
}
const triggerReload = () => {
timelineStatus.isLoaded = false
timelineStatus.isError = false
nextTick(() => {
scriptTag.value.src = 'https://platform.twitter.com/widgets.js'
})
}
onMounted(() => {
scriptTag.value.src = 'https://platform.twitter.com/widgets.js'
})
const handleError = () => {
timelineStatus.isLoaded = true
timelineStatus.isError = true
}
</script>
<template>
@ -22,13 +38,24 @@ onMounted(() => {
}"
class="overflow-y-auto nc-scrollbar-md w-full"
>
<div v-if="!isLoaded" class="flex items-center justify-center h-full w-full">
<div v-if="!timelineStatus.isLoaded" class="flex items-center justify-center h-full w-full">
<GeneralLoader size="xlarge" />
</div>
<div v-else-if="timelineStatus.isError" class="h-full flex justify-center items-center">
<FeedError page="twitter" @reload="triggerReload" />
</div>
<div class="mx-auto flex flex-col my-6 items-center">
<div style="min-width: 650px">
<a class="twitter-timeline" href="https://twitter.com/nocodb?ref_src=twsrc%5Etfw"></a>
<Script ref="scriptTag" async charset="utf-8" @load="handleIframeLoad"></Script>
<a data-chrome="nofooter" class="twitter-timeline" href="https://twitter.com/nocodb?ref_src=twsrc%5Etfw"></a>
<Script
v-if="!timelineStatus.isError"
ref="scriptTag"
async
charset="utf-8"
@load="handleIframeLoad"
@error="handleError"
></Script>
</div>
</div>
</div>

47
packages/nc-gui/composables/useProductFeed.ts

@ -1,3 +1,4 @@
import dayjs from 'dayjs'
import type { ProductFeedItem } from '../lib/types'
export const useProductFeed = createSharedComposable(() => {
@ -5,6 +6,8 @@ export const useProductFeed = createSharedComposable(() => {
const { $api } = useNuxtApp()
const { appInfo } = useGlobal()
const youtubeFeed = ref<ProductFeedItem[]>([])
const githubFeed = ref<ProductFeedItem[]>([])
@ -37,10 +40,6 @@ export const useProductFeed = createSharedComposable(() => {
const response = await $api.utils.feed({ page, per_page: 10, type })
if (type === 'all' && page === 1 && response.length) {
localStorage.setItem('last_published_at', response[0]['Published Time'] as string)
}
switch (type) {
case 'youtube':
youtubeFeed.value = [...youtubeFeed.value, ...response] as ProductFeedItem[]
@ -69,6 +68,45 @@ export const useProductFeed = createSharedComposable(() => {
}
}
const isNewFeedAvailable = ref(false)
const checkNewFeed = async () => {
try {
await loadFeed({ type: 'all', loadMore: false })
if (!socialFeed.value.length) return
const [latestFeed] = socialFeed.value
const lastFeedTime = localStorage.getItem('lastFeedPublishedTime')
const lastFeed = dayjs(lastFeedTime)
if (!lastFeed.isValid() || dayjs(latestFeed['Published Time']).isAfter(lastFeed)) {
isNewFeedAvailable.value = true
}
} catch (error) {
console.error('Error while checking new feed', error)
}
}
const intervalId = ref()
const checkFeedWithInterval = async () => {
await checkNewFeed()
intervalId.value = setTimeout(checkFeedWithInterval, 3 * 60 * 60 * 1000)
}
onMounted(() => {
if (appInfo.value.feedEnabled) {
checkFeedWithInterval()
}
})
onUnmounted(() => {
if (intervalId.value) {
clearTimeout(intervalId.value)
intervalId.value = null
}
})
return {
isErrorOccurred,
activeTab,
@ -76,5 +114,6 @@ export const useProductFeed = createSharedComposable(() => {
githubFeed,
socialFeed,
loadFeed,
isNewFeedAvailable,
}
})

Loading…
Cancel
Save