This commit is contained in:
Untone 2024-02-26 00:39:21 +03:00
commit 5092a98fba
5 changed files with 69 additions and 62 deletions

View File

@ -1,5 +1,5 @@
import { clsx } from 'clsx'
import { For, Show, createEffect, createSignal } from 'solid-js'
import { For, Show, createEffect, createSignal, on, onMount } from 'solid-js'
import { useFollowing } from '../../context/following'
import { useLocalize } from '../../context/localize'
import { apiClient } from '../../graphql/client/core'
@ -11,24 +11,29 @@ import styles from './AuthorsList.module.scss'
type Props = {
class?: string
query: 'shouts' | 'followers'
query: 'shouts' | 'authors'
searchQuery?: string
allAuthorsLength?: number
}
const PAGE_SIZE = 20
export const AuthorsList = (props: Props) => {
const { t } = useLocalize()
const { isOwnerSubscribed } = useFollowing()
const { authorsByShouts, authorsByFollowers } = useAuthorsStore()
const [loading, setLoading] = createSignal(false)
const [currentPage, setCurrentPage] = createSignal({ shouts: 0, followers: 0 })
const { authorsByShouts, authorsByFollowers } = useAuthorsStore()
const [allLoaded, setAllLoaded] = createSignal(false)
const fetchAuthors = async (queryType: 'shouts' | 'followers', page: number) => {
const fetchAuthors = async (queryType: 'shouts' | 'authors', page: number) => {
setLoading(true)
console.log('!!! AAA:')
const offset = PAGE_SIZE * page
const result = await apiClient.loadAuthorsBy({
by: { order: queryType },
limit: PAGE_SIZE,
offset: offset,
offset,
})
if (queryType === 'shouts') {
@ -41,25 +46,38 @@ export const AuthorsList = (props: Props) => {
}
const loadMoreAuthors = () => {
const queryType = props.query
const nextPage = currentPage()[queryType] + 1
fetchAuthors(queryType, nextPage).then(() =>
setCurrentPage({ ...currentPage(), [queryType]: nextPage }),
const nextPage = currentPage()[props.query] + 1
fetchAuthors(props.query, nextPage).then(() =>
setCurrentPage({ ...currentPage(), [props.query]: nextPage }),
)
}
createEffect(() => {
const queryType = props.query
if (
currentPage()[queryType] === 0 &&
(authorsByShouts().length === 0 || authorsByFollowers().length === 0)
) {
loadMoreAuthors()
}
})
createEffect(
on(
() => props.query,
(query) => {
const authorsList = query === 'shouts' ? authorsByShouts() : authorsByFollowers()
if (authorsList.length === 0 || currentPage()[query] === 0) {
setCurrentPage((prev) => ({ ...prev, [query]: 0 }))
fetchAuthors(query, 0).then(() => setCurrentPage((prev) => ({ ...prev, [query]: 1 })))
}
},
),
)
const authorsList = () => (props.query === 'shouts' ? authorsByShouts() : authorsByFollowers())
// TODO: do it with backend
// createEffect(() => {
// if (props.searchQuery) {
// // search logic
// }
// })
createEffect(() => {
setAllLoaded(authorsByShouts().length === authorsList.length)
})
return (
<div class={clsx(styles.AuthorsList, props.class)}>
<For each={authorsList()}>
@ -77,13 +95,17 @@ export const AuthorsList = (props: Props) => {
</div>
)}
</For>
<div class={styles.action}>
<Show when={!loading()}>
<Button value={t('Load more')} onClick={loadMoreAuthors} />
</Show>
<Show when={loading()}>
<InlineLoader />
</Show>
<div class="row">
<div class="col-lg-20 col-xl-18">
<div class={styles.action}>
<Show when={!loading() && authorsList().length > 0 && !allLoaded()}>
<Button value={t('Load more')} onClick={loadMoreAuthors} />
</Show>
<Show when={loading() && !allLoaded()}>
<InlineLoader />
</Show>
</div>
</div>
</div>
</div>
)

View File

@ -142,10 +142,8 @@ export const Header = (props: Props) => {
}
onMount(async () => {
if (window.location.pathname === '/' || window.location.pathname === '') {
const topics = await apiClient.getRandomTopics({ amount: RANDOM_TOPICS_COUNT })
setRandomTopics(topics)
}
const topics = await apiClient.getRandomTopics({ amount: RANDOM_TOPICS_COUNT })
setRandomTopics(topics)
})
const handleToggleMenuByLink = (event: MouseEvent, route: keyof typeof ROUTES) => {

View File

@ -28,6 +28,7 @@ type Props = {
export const AllAuthors = (props: Props) => {
const { t, lang } = useLocalize()
const [searchQuery, setSearchQuery] = createSignal('')
const ALPHABET =
lang() === 'ru' ? [...'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ@'] : [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ@']
const { searchParams, changeSearchParams } = useRouter<AllAuthorsPageSearchParams>()
@ -36,27 +37,22 @@ export const AllAuthors = (props: Props) => {
sortBy: searchParams().by || 'name',
})
const [searchQuery, setSearchQuery] = createSignal('')
createEffect(() => {
let by = searchParams().by
if (by) {
setAuthorsSort(by)
} else {
by = 'name'
changeSearchParams({ by })
}
const filteredAuthors = createMemo(() => {
const query = searchQuery().toLowerCase()
return sortedAuthors().filter((author) => {
return author.name.toLowerCase().includes(query) // Предполагаем, что у автора есть свойство name
})
})
const byLetter = createMemo<{ [letter: string]: Author[] }>(() => {
return sortedAuthors().reduce(
const byLetterFiltered = createMemo<{ [letter: string]: Author[] }>(() => {
return filteredAuthors().reduce(
(acc, author) => authorLetterReduce(acc, author, lang()),
{} as { [letter: string]: Author[] },
)
})
const sortedKeys = createMemo<string[]>(() => {
const keys = Object.keys(byLetter())
const keys = Object.keys(byLetterFiltered())
keys.sort()
keys.push(keys.shift())
return keys
@ -106,7 +102,7 @@ export const AllAuthors = (props: Props) => {
>
<a href="/authors?by=name">{t('By name')}</a>
</li>
<Show when={searchParams().by !== 'name'}>
<Show when={searchParams().by === 'name'}>
<li class="view-switcher__search">
<SearchField onChange={(value) => setSearchQuery(value)} />
</li>
@ -122,7 +118,7 @@ export const AllAuthors = (props: Props) => {
<For each={ALPHABET}>
{(letter, index) => (
<li>
<Show when={letter in byLetter()} fallback={letter}>
<Show when={letter in byLetterFiltered()} fallback={letter}>
<a
href={`/authors?by=name#letter-${index()}`}
onClick={(event) => {
@ -147,7 +143,7 @@ export const AllAuthors = (props: Props) => {
<div class="row">
<div class="col-lg-20">
<div class="row">
<For each={byLetter()[letter]}>
<For each={byLetterFiltered()[letter]}>
{(author) => (
<div class={clsx(styles.topic, 'topic col-sm-12 col-md-8')}>
<div class="topic-title">
@ -167,8 +163,12 @@ export const AllAuthors = (props: Props) => {
)}
</For>
</Show>
<Show when={searchParams().by !== 'name' && props.isLoaded} fallback={<Loading />}>
<AuthorsList query={searchParams().by === 'shouts' ? 'shouts' : 'followers'} />
<Show when={searchParams().by !== 'name' && props.isLoaded}>
<AuthorsList
allAuthorsLength={sortedAuthors()?.length}
searchQuery={searchQuery()}
query={searchParams().by === 'shouts' ? 'shouts' : 'authors'}
/>
</Show>
</div>
</Show>

View File

@ -175,7 +175,7 @@ export const AuthorView = (props: Props) => {
{t('Comments')}
</a>
<Show when={author().stat}>
<span class="view-switcher__counter">{author().stat.commented}</span>
<span class="view-switcher__counter">{author().stat.comments}</span>
</Show>
</li>
<li classList={{ 'view-switcher__item--selected': getPage().route === 'authorAbout' }}>

View File

@ -3,7 +3,6 @@ import { createSignal } from 'solid-js'
import { apiClient } from '../../graphql/client/core'
import { Author, QueryLoad_Authors_ByArgs } from '../../graphql/schema/core.gen'
import { byStat } from '../../utils/sortby'
export type AuthorsSortBy = 'shouts' | 'name' | 'followers'
type SortedAuthorsSetter = (prev: Author[]) => Author[]
@ -21,19 +20,7 @@ export const setAuthorsByShouts = (authors: SortedAuthorsSetter) => setSortedAut
export const setAuthorsByFollowers = (authors: SortedAuthorsSetter) => setSortedAuthorsByFollowers(authors)
const sortedAuthors = createLazyMemo(() => {
const authors = Object.values(authorEntities())
switch (sortAllBy()) {
case 'followers': {
return authors.sort(byStat('followers'))
}
case 'shouts': {
return authors.sort(byStat('shouts'))
}
case 'name': {
return authors.sort((a, b) => a.name.localeCompare(b.name))
}
}
return authors
return Object.values(authorEntities())
})
export const addAuthors = (authors: Author[]) => {