2024-09-17 08:11:35 +02:00
|
|
|
import type { Category, Project, ProjectRating, ProjectRatingItem, ProjectShallow } from '~/types'
|
2024-09-12 08:43:01 +02:00
|
|
|
import type { Asset } from '~/types/asset'
|
|
|
|
import type { Ecosystem } from '~/types/ecosystem'
|
|
|
|
import type { Feature } from '~/types/feature'
|
2024-09-17 08:11:35 +02:00
|
|
|
import type { Rank } from '~/types/rank'
|
2024-09-12 08:43:01 +02:00
|
|
|
import type { Usecase } from '~/types/usecase'
|
2023-12-19 18:43:42 +01:00
|
|
|
|
|
|
|
export const useData = defineStore('data', () => {
|
2024-09-18 10:48:08 +02:00
|
|
|
const projectPhase = useState<{ id: string, name: string }[]>('projectPhase')
|
|
|
|
const assetCustody = useState<{ id: string, name: string }[]>('assetCustody')
|
|
|
|
const signInRequirments = useState<{ id: string, name: string }[]>('signInRequirmenets')
|
2024-09-12 18:03:06 +02:00
|
|
|
|
2023-12-19 18:43:42 +01:00
|
|
|
const categories = useState<Category[]>('categories')
|
2024-09-12 08:43:01 +02:00
|
|
|
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')
|
2024-09-17 08:11:35 +02:00
|
|
|
const ranks = useState<Rank[]>('ranks')
|
|
|
|
|
2024-09-03 17:13:23 +02:00
|
|
|
const selectedCategoryId = useState(() => 'all')
|
2024-09-17 08:11:35 +02:00
|
|
|
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: '',
|
2024-09-17 08:11:35 +02:00
|
|
|
sortby: 'score',
|
|
|
|
sortDirection: 'desc',
|
2023-12-19 18:43:42 +01:00
|
|
|
})
|
|
|
|
const switcher = ref(true)
|
|
|
|
|
2024-09-17 08:11:35 +02:00
|
|
|
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, () => {
|
2024-09-17 08:11:35 +02:00
|
|
|
if (filter.query !== '') {
|
2023-12-19 18:43:42 +01:00
|
|
|
selectedCategoryId.value = 'all'
|
2024-09-17 08:11:35 +02:00
|
|
|
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[]
|
2024-09-23 21:14:59 +02:00
|
|
|
phases: { id: string, name: string }[]
|
|
|
|
custodys: { id: string, name: string }[]
|
|
|
|
requirements: { id: string, name: string }[]
|
2024-09-12 08:43:01 +02:00
|
|
|
usecases: Usecase[]
|
|
|
|
ecosystems: Ecosystem[]
|
|
|
|
assets: Asset[]
|
|
|
|
features: Feature[]
|
2024-09-17 08:11:35 +02:00
|
|
|
ranks: Rank[]
|
2023-12-19 18:43:42 +01:00
|
|
|
}>('/api/data')
|
2024-09-18 21:16:35 +02:00
|
|
|
data.projects.forEach(project => project.ratings = generateProjectRating(project))
|
2024-09-12 08:43:01 +02:00
|
|
|
projects.value = data.projects.map(project => ({
|
|
|
|
...project,
|
2024-09-18 20:46:47 +02:00
|
|
|
percentage: Math.round((project.ratings?.reduce((a, b) => a + b.points, 0) || 0) / 1.5),
|
2024-09-12 08:43:01 +02:00
|
|
|
})).filter(p => p.name)
|
2024-09-18 10:48:08 +02:00
|
|
|
|
|
|
|
categories.value = data.categories
|
2024-09-12 08:43:01 +02:00
|
|
|
usecases.value = data.usecases
|
|
|
|
ecosystems.value = data.ecosystems
|
|
|
|
assets.value = data.assets
|
|
|
|
features.value = data.features
|
2024-09-17 08:11:35 +02:00
|
|
|
ranks.value = data.ranks
|
2024-09-18 10:48:08 +02:00
|
|
|
|
2024-09-23 21:14:59 +02:00
|
|
|
projectPhase.value = data.phases?.map(p => ({ id: p.id.toLowerCase(), name: p.name }))
|
|
|
|
assetCustody.value = data.custodys.map(a => ({ id: a.id.toLowerCase(), name: a.name }))
|
|
|
|
signInRequirments.value = data.requirements.map(s => ({ id: s.id.toLowerCase(), name: s.name }))
|
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']
|
2024-06-27 12:33:30 +02:00
|
|
|
// 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
|
|
|
|
2024-06-27 12:33:30 +02: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',
|
2024-09-18 20:46:47 +02:00
|
|
|
percentage: project.percentage,
|
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,
|
2024-09-12 08:43:01 +02:00
|
|
|
categories: project.categories,
|
2024-09-17 08:11:35 +02:00
|
|
|
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)))
|
|
|
|
|
2024-09-17 08:11:35 +02:00
|
|
|
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 =>
|
2024-09-23 21:14:59 +02:00
|
|
|
selectedUsecaseId.value !== 'all' ? selectedUsecaseId.value === 'sunset' ? project.sunset : project.usecases?.map(u => u.toLowerCase()).includes(selectedUsecaseId.value.toLowerCase()) : true,
|
2024-09-17 08:11:35 +02:00
|
|
|
)
|
|
|
|
.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()
|
|
|
|
|
2024-09-17 08:11:35 +02:00
|
|
|
const filteredShallowProjects = getProjectsByFilters({ shallow: true })
|
2023-12-19 18:43:42 +01:00
|
|
|
.filter((project) => {
|
|
|
|
return (
|
|
|
|
project
|
2024-06-27 12:33:30 +02:00
|
|
|
&& 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')
|
2024-09-17 08:11:35 +02:00
|
|
|
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
|
|
|
|
})
|
|
|
|
|
2024-09-12 08:43:01 +02:00
|
|
|
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)
|
|
|
|
|
2024-09-23 21:14:59 +02:00
|
|
|
return groupedProjects.filter(group => group.projects.length > 0)
|
2024-09-12 08:43:01 +02:00
|
|
|
})
|
|
|
|
|
2023-12-19 18:43:42 +01:00
|
|
|
const filteredProjectsCount = computed(() => filteredProjects.value.length)
|
|
|
|
|
2024-09-17 08:11:35 +02:00
|
|
|
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
|
|
|
|
|
2024-09-20 12:13:27 +02:00
|
|
|
if (ref.condition.minLength !== undefined) {
|
2024-09-17 08:11:35 +02:00
|
|
|
value = (field as any[])?.length
|
|
|
|
if (value) {
|
|
|
|
isValid = value >= ref.condition.minLength
|
2024-09-17 09:05:34 +02:00
|
|
|
positive = `${value} ${ref.label.positive}${value > 1 ? 's' : ''}`
|
2024-09-17 08:11:35 +02:00
|
|
|
}
|
|
|
|
}
|
2024-09-20 12:13:27 +02:00
|
|
|
if (ref.condition.equals !== undefined) {
|
2024-09-17 08:11:35 +02:00
|
|
|
value = field
|
2024-09-20 12:13:27 +02:00
|
|
|
if (value !== undefined)
|
2024-09-17 08:11:35 +02:00
|
|
|
isValid = value === ref.condition.equals
|
|
|
|
}
|
|
|
|
|
2024-09-20 12:13:27 +02:00
|
|
|
if (ref.condition.exists !== undefined) {
|
2024-09-17 08:11:35 +02:00
|
|
|
value = field
|
2024-09-20 12:13:27 +02:00
|
|
|
if (value !== undefined)
|
2024-09-17 08:11:35 +02:00
|
|
|
isValid = !!value
|
|
|
|
}
|
|
|
|
rankPoints += isValid ? ref.points : 0
|
|
|
|
return {
|
|
|
|
isValid,
|
2024-09-17 09:05:34 +02:00
|
|
|
label: ref.label.name,
|
|
|
|
positive: positive ? positive : ref.label.positive,
|
|
|
|
negative: ref.label.negative,
|
2024-09-17 08:11:35 +02:00
|
|
|
value,
|
2024-09-17 09:05:34 +02:00
|
|
|
} as ProjectRatingItem
|
2024-09-17 08:11:35 +02:00
|
|
|
})
|
|
|
|
return {
|
|
|
|
type: rank.id,
|
|
|
|
name: rank.name,
|
|
|
|
items: ratingStats,
|
|
|
|
points: rankPoints,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
return projectRatings
|
|
|
|
}
|
|
|
|
|
2023-12-19 18:43:42 +01:00
|
|
|
return {
|
|
|
|
selectedCategoryId,
|
2024-09-17 08:11:35 +02:00
|
|
|
selectedUsecaseId,
|
|
|
|
selectedEcosystemId,
|
|
|
|
selectedAssetsUsedId,
|
|
|
|
selectedFeaturesId,
|
2023-12-19 18:43:42 +01:00
|
|
|
filter,
|
|
|
|
switcher,
|
|
|
|
categories,
|
2024-09-18 10:48:08 +02:00
|
|
|
projectPhase,
|
|
|
|
assetCustody,
|
|
|
|
signInRequirments,
|
2024-09-12 08:43:01 +02:00
|
|
|
usecases,
|
|
|
|
features,
|
|
|
|
ecosystems,
|
|
|
|
assets,
|
2023-12-19 18:43:42 +01:00
|
|
|
projects,
|
|
|
|
shallowProjects,
|
2024-09-12 08:43:01 +02:00
|
|
|
groupedProjectsPerCategory,
|
2023-12-19 18:43:42 +01:00
|
|
|
filteredProjectsCount,
|
|
|
|
fetchData,
|
|
|
|
getProjectById,
|
|
|
|
filteredProjects,
|
|
|
|
projectToShallow,
|
|
|
|
}
|
|
|
|
})
|