author-page-wip
This commit is contained in:
parent
25d217389b
commit
b7e775eeea
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -27,3 +27,4 @@ target
|
||||||
|
|
||||||
.output
|
.output
|
||||||
.vinxi
|
.vinxi
|
||||||
|
*.pem
|
||||||
|
|
57
README.en.md
Normal file
57
README.en.md
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
## Development setup recommendations
|
||||||
|
|
||||||
|
### How to start
|
||||||
|
|
||||||
|
Use `bun i`, `npm i`, `pnpm i` or `yarn` to install packages. Then generate cert and key file for devserver with `mkcert localhost`.
|
||||||
|
|
||||||
|
### Config of variables
|
||||||
|
|
||||||
|
- Use `.env` file to setup your own development environment
|
||||||
|
- Env vars with prefix `PUBLIC_` are widely used in `/src/utils/config.ts`
|
||||||
|
|
||||||
|
### Useful commands
|
||||||
|
|
||||||
|
run checks, fix styles, imports, formatting and autofixable linting errors:
|
||||||
|
```
|
||||||
|
bun run typecheck
|
||||||
|
bun run fix
|
||||||
|
```
|
||||||
|
|
||||||
|
## End-to-End (E2E) Tests
|
||||||
|
|
||||||
|
This directory contains end-to-end tests. These tests are written using [Playwright](https://playwright.dev/)
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
- `/tests/*`: This directory contains the test files.
|
||||||
|
- `/playwright.config.ts`: This is the configuration file for Playwright.
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
|
||||||
|
Follow these steps:
|
||||||
|
|
||||||
|
1. **Install dependencies**: Run `npm run e2e:install` to install the necessary dependencies for running the tests.
|
||||||
|
|
||||||
|
2. **Run the tests**: After using `npm run e2e:tests`.
|
||||||
|
|
||||||
|
### Additional Information
|
||||||
|
|
||||||
|
If workers is no needed use:
|
||||||
|
- `npx playwright test --project=webkit --workers 4`
|
||||||
|
|
||||||
|
For more information on how to write tests using Playwright - [Playwright documentation](https://playwright.dev/docs/intro).
|
||||||
|
|
||||||
|
### 🚀 Tests in CI Mode
|
||||||
|
|
||||||
|
Tests are executed within a GitHub workflow. We organize our tests into two main directories:
|
||||||
|
|
||||||
|
- `tests`: Contains tests that do not require authentication.
|
||||||
|
- `tests-with-auth`: Houses tests that interact with authenticated parts of the application.
|
||||||
|
|
||||||
|
🔧 **Configuration:**
|
||||||
|
|
||||||
|
Playwright is configured to utilize the `BASE_URL` environment variable. Ensure this is properly set in your CI configuration to point to the correct environment.
|
||||||
|
|
||||||
|
📝 **Note:**
|
||||||
|
|
||||||
|
After pages have been adjusted to work with authentication, all tests should be moved to the `tests` directory to streamline the testing process.
|
68
README.md
68
README.md
|
@ -1,63 +1,59 @@
|
||||||
## How to start
|
## Рекомендации по настройке разработки
|
||||||
|
|
||||||
Use Bun to manage packages.
|
### Как начать
|
||||||
|
|
||||||
```
|
Используйте `bun i`, `npm i`, `pnpm i` или `yarn`, чтобы установить пакеты. Затем сгенерируйте сертификат и файл ключа для devserver с помощью `mkcert localhost`.
|
||||||
bun i
|
|
||||||
```
|
### Настройка переменных
|
||||||
|
|
||||||
|
- Используйте файл `.env` для настройки переменных собственной среды разработки.
|
||||||
|
- Переменные окружения с префиксом `PUBLIC_` широко используются в `/src/utils/config.ts`.
|
||||||
|
|
||||||
|
### Полезные команды
|
||||||
|
|
||||||
|
Запуск проверки соответствия типов и автоматически исправить ошибки стилей, порядок импорта, форматирование:
|
||||||
|
|
||||||
## Useful commands
|
|
||||||
run checks
|
|
||||||
```
|
```
|
||||||
bun run typecheck
|
bun run typecheck
|
||||||
```
|
|
||||||
fix styles, imports, formatting and autofixable linting errors:
|
|
||||||
```
|
|
||||||
bun run fix
|
bun run fix
|
||||||
```
|
```
|
||||||
|
|
||||||
## Config of variables
|
|
||||||
|
|
||||||
- All vars are already in place and wroted in
|
## End-to-End (E2E) тесты
|
||||||
```
|
|
||||||
/src/utils/config.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
# End-to-End (E2E) Tests
|
End-to-end тесты написаны с использованием [Playwright](https://playwright.dev/).
|
||||||
|
|
||||||
This directory contains end-to-end tests. These tests are written using [Playwright](https://playwright.dev/)
|
### Структура
|
||||||
|
|
||||||
## Structure
|
- `/tests/*`: содержит файлы тестов
|
||||||
|
- `/playwright.config.ts`: конфиг для Playwright
|
||||||
|
|
||||||
- `/tests/*`: This directory contains the test files.
|
### Начало работы
|
||||||
- `/playwright.config.ts`: This is the configuration file for Playwright.
|
|
||||||
|
|
||||||
## Getting Started
|
Следуйте этим шагам:
|
||||||
|
|
||||||
Follow these steps:
|
1. **Установите зависимости**: Запустите `npm run e2e:install`, чтобы установить необходимые зависимости для выполнения тестов.
|
||||||
|
|
||||||
1. **Install dependencies**: Run `pnpm e2e:install` to install the necessary dependencies for running the tests.
|
2. **Запустите тесты**: После установки зависимостей используйте `npm run e2e:tests`.
|
||||||
|
|
||||||
2. **Run the tests**: After using `pnpm e2e:tests`.
|
### Дополнительная информация
|
||||||
|
|
||||||
## Additional Information
|
Для параллельного исполнения:
|
||||||
|
|
||||||
If workers is no needed use:
|
|
||||||
- `npx playwright test --project=webkit --workers 4`
|
- `npx playwright test --project=webkit --workers 4`
|
||||||
|
|
||||||
For more information on how to write tests using Playwright - [Playwright documentation](https://playwright.dev/docs/intro).
|
Для получения дополнительной информации о написании тестов с использованием Playwright - [Документация Playwright](https://playwright.dev/docs/intro).
|
||||||
|
|
||||||
## 🚀 Tests in CI Mode
|
### 🚀 Тесты в режиме CI
|
||||||
|
|
||||||
Tests are executed within a GitHub workflow. We organize our tests into two main directories:
|
Тесты выполняются в рамках GitHub workflow. Мы организуем наши тесты в две основные директории:
|
||||||
|
|
||||||
- `tests`: Contains tests that do not require authentication.
|
- `tests`: Содержит тесты, которые не требуют аутентификации.
|
||||||
- `tests-with-auth`: Houses tests that interact with authenticated parts of the application.
|
- `tests-with-auth`: Содержит тесты, которые взаимодействуют с аутентифицированными частями приложения.
|
||||||
|
|
||||||
🔧 **Configuration:**
|
🔧 **Конфигурация:**
|
||||||
|
|
||||||
Playwright is configured to utilize the `BASE_URL` environment variable. Ensure this is properly set in your CI configuration to point to the correct environment.
|
Playwright настроен на использование переменной окружения `BASE_URL`. Убедитесь, что она правильно установлена в вашей конфигурации CI для указания на правильную среду.
|
||||||
|
|
||||||
📝 **Note:**
|
📝 **Примечание:**
|
||||||
|
|
||||||
After pages have been adjusted to work with authentication, all tests should be moved to the `tests` directory to streamline the testing process.
|
После того как страницы были настроены для работы с аутентификацией, все тесты должны быть перемещены в директорию `tests` для упрощения процесса тестирования.
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { SolidStartInlineConfig, defineConfig } from '@solidjs/start/config'
|
import { SolidStartInlineConfig, defineConfig } from '@solidjs/start/config'
|
||||||
|
import { visualizer } from "rollup-plugin-visualizer"
|
||||||
|
import mkcert from 'vite-plugin-mkcert'
|
||||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
||||||
import sassDts from 'vite-plugin-sass-dts'
|
import sassDts from 'vite-plugin-sass-dts'
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ export default defineConfig({
|
||||||
vite: {
|
vite: {
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
plugins: [
|
plugins: [
|
||||||
|
mkcert(),
|
||||||
nodePolyfills({
|
nodePolyfills({
|
||||||
include: ['path', 'stream', 'util'],
|
include: ['path', 'stream', 'util'],
|
||||||
exclude: ['http'],
|
exclude: ['http'],
|
||||||
|
@ -43,7 +46,10 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
chunkSizeWarningLimit: 1024,
|
chunkSizeWarningLimit: 1024,
|
||||||
target: 'esnext'
|
target: 'esnext',
|
||||||
|
rollupOptions: {
|
||||||
|
plugins: [visualizer(), ]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
https: true
|
https: true
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
"prosemirror-history": "^1.4.1",
|
"prosemirror-history": "^1.4.1",
|
||||||
"prosemirror-trailing-node": "^2.0.8",
|
"prosemirror-trailing-node": "^2.0.8",
|
||||||
"prosemirror-view": "^1.33.8",
|
"prosemirror-view": "^1.33.8",
|
||||||
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"sass": "1.76.0",
|
"sass": "1.76.0",
|
||||||
"solid-js": "^1.8.18",
|
"solid-js": "^1.8.18",
|
||||||
"solid-popper": "^0.3.0",
|
"solid-popper": "^0.3.0",
|
||||||
|
@ -106,6 +107,7 @@
|
||||||
"typograf": "^7.4.1",
|
"typograf": "^7.4.1",
|
||||||
"uniqolor": "^1.1.1",
|
"uniqolor": "^1.1.1",
|
||||||
"vinxi": "^0.3.14",
|
"vinxi": "^0.3.14",
|
||||||
|
"vite-plugin-mkcert": "^1.17.5",
|
||||||
"vite-plugin-node-polyfills": "^0.22.0",
|
"vite-plugin-node-polyfills": "^0.22.0",
|
||||||
"vite-plugin-sass-dts": "^1.3.24",
|
"vite-plugin-sass-dts": "^1.3.24",
|
||||||
"y-prosemirror": "1.2.9",
|
"y-prosemirror": "1.2.9",
|
||||||
|
|
|
@ -28,35 +28,42 @@ import styles from './Author.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
authorSlug: string
|
authorSlug: string
|
||||||
|
selectedTab: string
|
||||||
shouts?: Shout[]
|
shouts?: Shout[]
|
||||||
author?: Author
|
author?: Author
|
||||||
topics?: Topic[]
|
topics?: Topic[]
|
||||||
selectedTab: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 12
|
export const PRERENDERED_ARTICLES_COUNT = 12
|
||||||
const LOAD_MORE_PAGE_SIZE = 9
|
const LOAD_MORE_PAGE_SIZE = 9
|
||||||
|
|
||||||
export const AuthorView = (props: Props) => {
|
export const AuthorView = (props: Props) => {
|
||||||
console.debug('[components.AuthorView] reactive context init...')
|
// contexts
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const params = useParams()
|
|
||||||
const { followers: myFollowers, follows: myFollows } = useFollowing()
|
|
||||||
const { session } = useSession()
|
|
||||||
const me = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
|
|
||||||
const [authorSlug, setSlug] = createSignal(props.authorSlug)
|
|
||||||
const { sortedFeed } = useFeed()
|
|
||||||
const loc = useLocation()
|
const loc = useLocation()
|
||||||
|
const params = useParams()
|
||||||
|
const { session } = useSession()
|
||||||
|
const { query } = useGraphQL()
|
||||||
|
const { sortedFeed } = useFeed()
|
||||||
|
const { loadAuthor, authorsEntities } = useAuthors()
|
||||||
|
const { followers: myFollowers, follows: myFollows } = useFollowing()
|
||||||
|
|
||||||
|
// signals
|
||||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
const [isBioExpanded, setIsBioExpanded] = createSignal(false)
|
const [isBioExpanded, setIsBioExpanded] = createSignal(false)
|
||||||
const { loadAuthor, authorsEntities } = useAuthors()
|
|
||||||
const [author, setAuthor] = createSignal<Author>()
|
const [author, setAuthor] = createSignal<Author>()
|
||||||
const [followers, setFollowers] = createSignal<Author[]>([] as Author[])
|
const [followers, setFollowers] = createSignal<Author[]>([] as Author[])
|
||||||
const [following, changeFollowing] = createSignal<Array<Author | Topic>>([] as Array<Author | Topic>) // flat AuthorFollowsResult
|
const [following, changeFollowing] = createSignal<Array<Author | Topic>>([] as Array<Author | Topic>) // flat AuthorFollowsResult
|
||||||
const [showExpandBioControl, setShowExpandBioControl] = createSignal(false)
|
const [showExpandBioControl, setShowExpandBioControl] = createSignal(false)
|
||||||
const [commented, setCommented] = createSignal<Reaction[]>([])
|
const [commented, setCommented] = createSignal<Reaction[]>([])
|
||||||
const { query } = useGraphQL()
|
|
||||||
|
|
||||||
|
// derivatives
|
||||||
|
const me = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
|
||||||
|
const pages = createMemo<Shout[][]>(() =>
|
||||||
|
splitToPages(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
|
||||||
|
)
|
||||||
|
|
||||||
|
// fx
|
||||||
// пагинация загрузки ленты постов
|
// пагинация загрузки ленты постов
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
saveScrollPosition()
|
saveScrollPosition()
|
||||||
|
@ -74,6 +81,7 @@ export const AuthorView = (props: Props) => {
|
||||||
const [isFetching, setIsFetching] = createSignal(false)
|
const [isFetching, setIsFetching] = createSignal(false)
|
||||||
createEffect(
|
createEffect(
|
||||||
on([() => session()?.user?.app_data?.profile, () => props.authorSlug || ''], async ([me, slug]) => {
|
on([() => session()?.user?.app_data?.profile, () => props.authorSlug || ''], async ([me, slug]) => {
|
||||||
|
console.debug('check if my profile')
|
||||||
const my = slug && me?.slug === slug
|
const my = slug && me?.slug === slug
|
||||||
if (my) {
|
if (my) {
|
||||||
console.debug('[Author] my profile precached')
|
console.debug('[Author] my profile precached')
|
||||||
|
@ -84,29 +92,27 @@ export const AuthorView = (props: Props) => {
|
||||||
}
|
}
|
||||||
} else if (slug && !isFetching()) {
|
} else if (slug && !isFetching()) {
|
||||||
setIsFetching(true)
|
setIsFetching(true)
|
||||||
setSlug(slug)
|
|
||||||
await loadAuthor({ slug })
|
await loadAuthor({ slug })
|
||||||
setIsFetching(false) // Сброс состояния загрузки после завершения
|
setIsFetching(false) // Сброс состояния загрузки после завершения
|
||||||
}
|
}
|
||||||
})
|
}, {defer: true})
|
||||||
)
|
)
|
||||||
|
|
||||||
// 2 // догружает подписки автора
|
// 2 // догружает подписки автора
|
||||||
createEffect(
|
createEffect(
|
||||||
on(
|
on(
|
||||||
[followers, () => props.author || authorsEntities()[authorSlug()]],
|
() => authorsEntities()[props.author?.slug || props.authorSlug || ''],
|
||||||
async ([current, found]) => {
|
async (found) => {
|
||||||
if (current) return
|
|
||||||
if (!found) return
|
if (!found) return
|
||||||
setAuthor(found)
|
setAuthor(found)
|
||||||
console.info(`[Author] profile for @${authorSlug()} fetched`)
|
console.info(`[Author] profile for @${found.slug} fetched`)
|
||||||
const followsResp = await query(getAuthorFollowsQuery, { slug: authorSlug() }).toPromise()
|
const followsResp = await query(getAuthorFollowsQuery, { slug: found.slug }).toPromise()
|
||||||
const follows = followsResp?.data?.get_author_followers || {}
|
const follows = followsResp?.data?.get_author_followers || {}
|
||||||
changeFollowing([...(follows?.authors || []), ...(follows?.topics || [])])
|
changeFollowing([...(follows?.authors || []), ...(follows?.topics || [])])
|
||||||
console.info(`[Author] follows for @${authorSlug()} fetched`)
|
console.info(`[Author] follows for @${found.slug} fetched`)
|
||||||
const followersResp = await query(getAuthorFollowersQuery, { slug: authorSlug() }).toPromise()
|
const followersResp = await query(getAuthorFollowersQuery, { slug: found.slug }).toPromise()
|
||||||
setFollowers(followersResp?.data?.get_author_followers || [])
|
setFollowers(followersResp?.data?.get_author_followers || [])
|
||||||
console.info(`[Author] followers for @${authorSlug()} fetched`)
|
console.info(`[Author] followers for @${found.slug} fetched`)
|
||||||
setIsFetching(false)
|
setIsFetching(false)
|
||||||
},
|
},
|
||||||
{ defer: true }
|
{ defer: true }
|
||||||
|
@ -120,33 +126,32 @@ export const AuthorView = (props: Props) => {
|
||||||
async (profile: Author) => {
|
async (profile: Author) => {
|
||||||
if (!commented() && profile) {
|
if (!commented() && profile) {
|
||||||
await loadMore()
|
await loadMore()
|
||||||
|
|
||||||
const commentsFetcher = loadReactions({
|
const commentsFetcher = loadReactions({
|
||||||
by: { comment: true, created_by: profile.id }
|
by: { comment: true, created_by: profile.id }
|
||||||
})
|
})
|
||||||
const ccc = await commentsFetcher()
|
const ccc = await commentsFetcher()
|
||||||
if (ccc) setCommented((_) => ccc || [])
|
if (ccc) setCommented((_) => ccc || [])
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
// { defer: true },
|
// { defer: true },
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// event handlers
|
||||||
let bioContainerRef: HTMLDivElement
|
let bioContainerRef: HTMLDivElement
|
||||||
let bioWrapperRef: HTMLDivElement
|
let bioWrapperRef: HTMLDivElement
|
||||||
const checkBioHeight = () => {
|
const checkBioHeight = () => {
|
||||||
|
console.debug('[AuthorView] mounted, checking bio height...')
|
||||||
if (bioContainerRef) {
|
if (bioContainerRef) {
|
||||||
setShowExpandBioControl(bioContainerRef.offsetHeight > bioWrapperRef.offsetHeight)
|
setShowExpandBioControl(bioContainerRef.offsetHeight > bioWrapperRef.offsetHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const pages = createMemo<Shout[][]>(() =>
|
|
||||||
splitToPages(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
|
|
||||||
)
|
|
||||||
const handleDeleteComment = (id: number) => {
|
const handleDeleteComment = (id: number) => {
|
||||||
setCommented((prev) => (prev || []).filter((comment) => comment.id !== id))
|
setCommented((prev) => (prev || []).filter((comment) => comment.id !== id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// on load
|
||||||
onMount(checkBioHeight)
|
onMount(checkBioHeight)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -95,6 +95,7 @@ export const AuthorsProvider = (props: { children: JSX.Element }) => {
|
||||||
const fetcher = await getAuthor(opts)
|
const fetcher = await getAuthor(opts)
|
||||||
const author = await fetcher()
|
const author = await fetcher()
|
||||||
if (author) addAuthor(author as Author)
|
if (author) addAuthor(author as Author)
|
||||||
|
console.debug('Loaded author:', author)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading author:', error)
|
console.error('Error loading author:', error)
|
||||||
throw error
|
throw error
|
||||||
|
|
|
@ -106,7 +106,7 @@ export const loadFollowersByTopic = (slug: string) => {
|
||||||
// TODO: paginate topic followers
|
// TODO: paginate topic followers
|
||||||
return cache(async () => {
|
return cache(async () => {
|
||||||
const resp = await defaultClient.query(loadFollowersByTopicQuery, { slug }).toPromise()
|
const resp = await defaultClient.query(loadFollowersByTopicQuery, { slug }).toPromise()
|
||||||
const result = resp?.data?.load_authors_by
|
const result = resp?.data?.get_topic_followers
|
||||||
if (result) return result as Author[]
|
if (result) return result as Author[]
|
||||||
}, `topic-${slug}`)
|
}, `topic-${slug}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ const fetchAllTopics = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchAuthor = async (slug: string) => {
|
const fetchAuthor = async (slug: string) => {
|
||||||
const authorFetcher = loadAuthors({ by: { slug }, limit: 1 } as QueryLoad_Authors_ByArgs)
|
const authorFetcher = loadAuthors({ by: { slug }, limit: 1, offset: 0 } as QueryLoad_Authors_ByArgs)
|
||||||
const aaa = await authorFetcher()
|
const aaa = await authorFetcher()
|
||||||
return aaa?.[0]
|
return aaa?.[0]
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,8 @@ export default (props: RouteSectionProps<{ articles: Shout[]; author: Author; to
|
||||||
? getImageUrl(author()?.pic || '', { width: 1200 })
|
? getImageUrl(author()?.pic || '', { width: 1200 })
|
||||||
: getImageUrl('production/image/logo_image.png')
|
: getImageUrl('production/image/logo_image.png')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const selectedTab = createMemo(() => params.tab in ['followers', 'shouts'] ? params.tab : 'name')
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary fallback={(_err) => <FourOuFourView />}>
|
<ErrorBoundary fallback={(_err) => <FourOuFourView />}>
|
||||||
<Suspense fallback={<Loading />}>
|
<Suspense fallback={<Loading />}>
|
||||||
|
@ -91,9 +93,9 @@ export default (props: RouteSectionProps<{ articles: Shout[]; author: Author; to
|
||||||
<ReactionsProvider>
|
<ReactionsProvider>
|
||||||
<AuthorView
|
<AuthorView
|
||||||
author={author() as Author}
|
author={author() as Author}
|
||||||
|
selectedTab={selectedTab()}
|
||||||
authorSlug={params.slug}
|
authorSlug={params.slug}
|
||||||
shouts={articles() as Shout[]}
|
shouts={articles() as Shout[]}
|
||||||
selectedTab={'shouts'}
|
|
||||||
topics={topics()}
|
topics={topics()}
|
||||||
/>
|
/>
|
||||||
</ReactionsProvider>
|
</ReactionsProvider>
|
|
@ -1,104 +0,0 @@
|
||||||
import { RouteSectionProps, createAsync, useParams } from '@solidjs/router'
|
|
||||||
import { ErrorBoundary, Suspense, createEffect, createMemo } from 'solid-js'
|
|
||||||
import { AuthorView } from '~/components/Views/Author'
|
|
||||||
import { FourOuFourView } from '~/components/Views/FourOuFour'
|
|
||||||
import { Loading } from '~/components/_shared/Loading'
|
|
||||||
import { PageLayout } from '~/components/_shared/PageLayout'
|
|
||||||
import { useAuthors } from '~/context/authors'
|
|
||||||
import { useLocalize } from '~/context/localize'
|
|
||||||
import { ReactionsProvider } from '~/context/reactions'
|
|
||||||
import { loadAuthors, loadShouts, loadTopics } from '~/graphql/api/public'
|
|
||||||
import {
|
|
||||||
Author,
|
|
||||||
LoadShoutsOptions,
|
|
||||||
QueryLoad_Authors_ByArgs,
|
|
||||||
Shout,
|
|
||||||
Topic
|
|
||||||
} from '~/graphql/schema/core.gen'
|
|
||||||
import { getImageUrl } from '~/lib/getImageUrl'
|
|
||||||
import { SHOUTS_PER_PAGE } from '../../(home)'
|
|
||||||
|
|
||||||
const fetchAuthorShouts = async (slug: string, offset?: number) => {
|
|
||||||
const opts: LoadShoutsOptions = { filters: { author: slug }, limit: SHOUTS_PER_PAGE, offset }
|
|
||||||
const shoutsLoader = loadShouts(opts)
|
|
||||||
return await shoutsLoader()
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchAllTopics = async () => {
|
|
||||||
const topicsFetcher = loadTopics()
|
|
||||||
return await topicsFetcher()
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchAuthor = async (slug: string) => {
|
|
||||||
const authorFetcher = loadAuthors({ by: { slug }, limit: 1 } as QueryLoad_Authors_ByArgs)
|
|
||||||
const aaa = await authorFetcher()
|
|
||||||
return aaa?.[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const route = {
|
|
||||||
load: async ({ params, location: { query } }: RouteSectionProps<{ articles: Shout[] }>) => {
|
|
||||||
const offset: number = Number.parseInt(query.offset, 10)
|
|
||||||
const result = await fetchAuthorShouts(params.slug, offset)
|
|
||||||
return {
|
|
||||||
author: await fetchAuthor(params.slug),
|
|
||||||
shouts: result || [],
|
|
||||||
topics: await fetchAllTopics()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (props: RouteSectionProps<{ articles: Shout[]; author: Author; topics: Topic[] }>) => {
|
|
||||||
const params = useParams()
|
|
||||||
const { addAuthor } = useAuthors()
|
|
||||||
const articles = createAsync(
|
|
||||||
async () => props.data.articles || (await fetchAuthorShouts(params.slug)) || []
|
|
||||||
)
|
|
||||||
const author = createAsync(async () => {
|
|
||||||
const a = props.data.author || (await fetchAuthor(params.slug))
|
|
||||||
addAuthor(a)
|
|
||||||
return a
|
|
||||||
})
|
|
||||||
const topics = createAsync(async () => props.data.topics || (await fetchAllTopics()))
|
|
||||||
const { t } = useLocalize()
|
|
||||||
const title = createMemo(() => `${author()?.name || ''}`)
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (author()) {
|
|
||||||
console.debug('[routes] author/[slug] author loaded fx')
|
|
||||||
window?.gtag?.('event', 'page_view', {
|
|
||||||
page_title: author()?.name || '',
|
|
||||||
page_location: window?.location.href || '',
|
|
||||||
page_path: window?.location.pathname || ''
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const cover = createMemo(() =>
|
|
||||||
author()?.pic
|
|
||||||
? getImageUrl(author()?.pic || '', { width: 1200 })
|
|
||||||
: getImageUrl('production/image/logo_image.png')
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
<ErrorBoundary fallback={(_err) => <FourOuFourView />}>
|
|
||||||
<Suspense fallback={<Loading />}>
|
|
||||||
<PageLayout
|
|
||||||
title={`${t('Discours')} :: ${title()}`}
|
|
||||||
headerTitle={author()?.name || ''}
|
|
||||||
slug={author()?.slug}
|
|
||||||
desc={author()?.about || author()?.bio || ''}
|
|
||||||
cover={cover()}
|
|
||||||
>
|
|
||||||
<ReactionsProvider>
|
|
||||||
<AuthorView
|
|
||||||
author={author() as Author}
|
|
||||||
authorSlug={params.slug}
|
|
||||||
shouts={articles() as Shout[]}
|
|
||||||
selectedTab={params.tab}
|
|
||||||
topics={topics()}
|
|
||||||
/>
|
|
||||||
</ReactionsProvider>
|
|
||||||
</PageLayout>
|
|
||||||
</Suspense>
|
|
||||||
</ErrorBoundary>
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user