explorer-app/composables/useData.ts

284 lines
9.5 KiB
TypeScript
Raw Normal View History

import type { Category, Project, ProjectRating, ProjectRatingItem, ProjectShallow } from '~/types'
import type { Asset } from '~/types/asset'
import type { Ecosystem } from '~/types/ecosystem'
import type { Feature } from '~/types/feature'
import type { Rank } from '~/types/rank'
import type { Usecase } from '~/types/usecase'
2023-12-19 18:43:42 +01:00
export const useData = defineStore('data', () => {
const categories = useState<Category[]>('categories')
const usecases = useState<Usecase[]>('usecases')
const features = useState<Feature[]>('features')
const assets = useState<Asset[]>('assets')
const ecosystems = useState<Ecosystem[]>('ecosystems')
2023-12-19 18:43:42 +01:00
const projects = useState<Project[]>('projects')
const ranks = useState<Rank[]>('ranks')
const selectedCategoryId = useState(() => 'all')
const selectedUsecaseId = useState(() => 'all')
const selectedEcosystemId = useState(() => 'all')
const selectedAssetsUsedId = useState(() => 'all')
const selectedFeaturesId = useState(() => 'all')
2023-12-19 18:43:42 +01:00
const filter = reactive({
query: '',
sortby: 'score',
sortDirection: 'desc',
2023-12-19 18:43:42 +01:00
})
const switcher = ref(true)
watch([selectedCategoryId, selectedUsecaseId, selectedEcosystemId, selectedAssetsUsedId, selectedFeaturesId], () => {
if (selectedCategoryId.value !== 'all' || selectedUsecaseId.value !== 'all' || selectedEcosystemId.value !== 'all' || selectedAssetsUsedId.value !== 'all' || selectedFeaturesId.value !== 'all')
2023-12-19 18:43:42 +01:00
filter.query = ''
})
watch(filter, () => {
if (filter.query !== '') {
2023-12-19 18:43:42 +01:00
selectedCategoryId.value = 'all'
selectedUsecaseId.value = 'all'
selectedEcosystemId.value = 'all'
selectedAssetsUsedId.value = 'all'
selectedFeaturesId.value = 'all'
}
2023-12-19 18:43:42 +01:00
})
const fetchData = async () => {
try {
const data = await $fetch<{
categories: Category[]
projects: Project[]
usecases: Usecase[]
ecosystems: Ecosystem[]
assets: Asset[]
features: Feature[]
ranks: Rank[]
2023-12-19 18:43:42 +01:00
}>('/api/data')
projects.value = data.projects.map(project => ({
...project,
ratings: generateProjectRating(project),
})).filter(p => p.name)
2023-12-19 18:43:42 +01:00
categories.value = data.categories.map((c) => {
c.projectsCount = projects.value.filter(p =>
p.categories?.includes(c.id),
).length
return c
}).filter(c => c.projectsCount > 0)
usecases.value = data.usecases
ecosystems.value = data.ecosystems
assets.value = data.assets
features.value = data.features
ranks.value = data.ranks
2023-12-19 18:43:42 +01:00
}
catch (e) {
console.error(e)
return false
}
return true
}
const projectToShallow = (project: Project): ProjectShallow => {
const availableSupport = () => {
const filteredKeys = ['forum', 'discord', 'twitter', 'lens', 'farcaster', 'telegram']
// if (typeof project.links === 'object' && (project.links !== null || project.links !== undefined))
2024-06-27 13:00:42 +02:00
if (project.links === null || project.links === undefined)
return 0
2023-12-19 18:43:42 +01:00
if (typeof project.links === 'object' && Object.keys(project.links).length > 0)
return Object.keys(project.links).filter(key => filteredKeys.includes(key)).length
2023-12-19 18:43:42 +01:00
}
return {
id: project.id,
title1: project.name,
description: project.description ?? 'N/A',
percentage: Math.round((project.ratings?.reduce((a, b) => a + b.points, 0) || 0) / 1.5),
2023-12-19 18:43:42 +01:00
forum: project.links?.forum,
explorer: project.links?.block_explorer,
twitter: project.links?.twitter,
coingecko: project.links?.coingecko,
newsletter: project.links?.rss_feed,
github: project.links?.github,
website: project.links?.web,
readyness: project.project_status?.version,
team: project.team,
docs: project.links?.docs,
audits: project.audits,
support: availableSupport(),
image: project.logos?.[0]?.url ?? '',
anonymity: true,
categories: project.categories,
usecases: project.usecases,
ecosystem: project.ecosystem,
assets_used: project.assets_used,
ratings: project.ratings,
2023-12-19 18:43:42 +01:00
}
}
const shallowProjects = computed(() => projects.value.map(project => projectToShallow(project)))
const getProjectsByFilters = <T extends ProjectShallow>(options?: { shallow: boolean }): T[] => {
const filteredProjects = projects.value
.filter(project =>
selectedCategoryId.value !== 'all' ? project.categories.includes(selectedCategoryId.value) : true,
)
.filter(project =>
selectedUsecaseId.value !== 'all' ? project.usecases?.map(u => u.toLowerCase()).includes(selectedUsecaseId.value.toLowerCase()) : true,
)
.filter(project =>
selectedEcosystemId.value !== 'all' ? project.ecosystem?.map(e => e.toLowerCase()).includes(selectedEcosystemId.value.toLowerCase()) : true,
)
.filter(project =>
selectedAssetsUsedId.value !== 'all' ? project.assets_used?.map(a => a.toLowerCase()).includes(selectedAssetsUsedId.value.toLowerCase()) : true,
)
.filter(project =>
selectedFeaturesId.value !== 'all' ? project.technology?.features?.map(f => f.toLowerCase()).includes(selectedFeaturesId.value.toLowerCase()) : true,
)
return (filteredProjects.map(project => options?.shallow ? projectToShallow(project) : project) as T[])
2023-12-19 18:43:42 +01:00
}
const getProjectById = <T extends Project | ProjectShallow>(id: string, options?: { shallow: boolean }): T => {
const project = projects.value.find(project => project.id === id)
return (options?.shallow && project ? projectToShallow(project) : project) as T
}
const filteredProjects = computed(() => {
if (!projects.value)
return []
const query = filter.query.toLowerCase()
const filteredShallowProjects = getProjectsByFilters({ shallow: true })
2023-12-19 18:43:42 +01:00
.filter((project) => {
return (
project
&& project.title1
&& project.title1.toLowerCase().includes(query)
2023-12-19 18:43:42 +01:00
)
}).filter((project) => {
if (filter.sortby === 'anonymity')
return project.anonymity === true
else
return true
}).sort((a, b) => {
if (filter.sortby === 'score')
if (filter.sortDirection === 'asc')
return a.percentage - b.percentage
else
return b.percentage - a.percentage
if (filter.sortby === 'title')
if (filter.sortDirection === 'asc')
return a.title1.toLowerCase().localeCompare(b.title1.toLowerCase())
else
return b.title1.toLowerCase().localeCompare(a.title1.toLowerCase())
if (filter.sortby === 'openess' || filter.sortby === 'technology' || filter.sortby === 'privacy') {
const scoreA = a.ratings?.find(r => r.type === filter.sortby)?.points || 0
const scoreB = b.ratings?.find(r => r.type === filter.sortby)?.points || 0
if (filter.sortDirection === 'asc')
return scoreB - scoreA
else
return scoreA - scoreB
}
2023-12-19 18:43:42 +01:00
else
return 0
})
return filteredShallowProjects
})
const groupedProjectsPerCategory = computed(() => {
const groupedProjects = categories.value.map((category) => {
// Find all projects that include this category
const projectsInCategory = filteredProjects.value.filter(project =>
project.categories.includes(category.id),
)
return {
title: category.name,
projects: projectsInCategory,
}
}).sort((a, b) => b.projects.length - a.projects.length)
return groupedProjects
})
2023-12-19 18:43:42 +01:00
const filteredProjectsCount = computed(() => filteredProjects.value.length)
const getNestedField = (project: Project, field: string) => {
const fields = field.split('.')
return fields.reduce((acc: any, curr: string) => {
return acc && acc[curr as keyof typeof acc]
}, project)
}
const generateProjectRating = (project: Project) => {
const projectRatings: ProjectRating[] = ranks.value?.map((rank) => {
let rankPoints = 0
const ratingStats: ProjectRatingItem[] = rank.references?.map((ref) => {
let isValid = false
const field = ref.field.includes('.') ? getNestedField(project, ref.field) : project[ref.field]
let value
let positive
if (ref.condition.minLength) {
value = (field as any[])?.length
if (value) {
isValid = value >= ref.condition.minLength
positive = `${value} ${ref.positive}${value > 1 ? 's' : ''}`
}
}
if (ref.condition.equals) {
value = field
if (value)
isValid = value === ref.condition.equals
}
if (ref.condition.exists) {
value = field
if (value)
isValid = !!value
}
rankPoints += isValid ? ref.points : 0
return {
isValid,
label: ref.label,
positive: positive ? positive : ref.positive,
negative: ref.negative,
value,
}
})
return {
type: rank.id,
name: rank.name,
items: ratingStats,
points: rankPoints,
}
})
return projectRatings
}
2023-12-19 18:43:42 +01:00
return {
selectedCategoryId,
selectedUsecaseId,
selectedEcosystemId,
selectedAssetsUsedId,
selectedFeaturesId,
2023-12-19 18:43:42 +01:00
filter,
switcher,
categories,
usecases,
features,
ecosystems,
assets,
2023-12-19 18:43:42 +01:00
projects,
shallowProjects,
groupedProjectsPerCategory,
2023-12-19 18:43:42 +01:00
filteredProjectsCount,
fetchData,
getProjectById,
filteredProjects,
projectToShallow,
}
})