Hotfix/all authors bugfix (#418)

bufgix to authors
This commit is contained in:
Ilya Y 2024-02-25 10:31:11 +03:00 committed by GitHub
parent fe9fd37d9d
commit 73e1f575f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 66 additions and 57 deletions

View File

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

View File

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

View File

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