Feature/auth guard update (#230)

- add AuthGuard on myFeed
- make AuthGuard closable with redirect to MainPage
This commit is contained in:
Ilya Y 2023-09-24 17:55:46 +03:00 committed by GitHub
parent bfc6599149
commit 8a71cb41ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 182 additions and 166 deletions

View File

@ -60,7 +60,6 @@ export const FullArticle = (props: Props) => {
}, 'bookmark')
}
console.log('!!! props.article.media:', props.article.media)
const body = createMemo(() => {
if (props.article.layout === 'literature') {
try {

View File

@ -4,11 +4,16 @@ import { hideModal, showModal } from '../../stores/ui'
type Props = {
children: JSX.Element
disabled?: boolean
}
export const AuthGuard = (props: Props) => {
const { isAuthenticated, isSessionLoaded } = useSession()
createEffect(() => {
if (props.disabled) {
return
}
if (isSessionLoaded()) {
if (isAuthenticated()) {
hideModal()
@ -18,5 +23,5 @@ export const AuthGuard = (props: Props) => {
}
})
return <Show when={isSessionLoaded() && isAuthenticated()}>{props.children}</Show>
return <Show when={(isSessionLoaded() && isAuthenticated()) || props.disabled}>{props.children}</Show>
}

View File

@ -5,6 +5,8 @@ import { hideModal, useModalStore } from '../../../stores/ui'
import { useEscKeyDownHandler } from '../../../utils/useEscKeyDownHandler'
import styles from './Modal.module.scss'
import { redirectPage } from '@nanostores/router'
import { router } from '../../../stores/router'
interface Props {
name: string
@ -22,9 +24,11 @@ export const Modal = (props: Props) => {
const allowClose = createMemo(() => props.allowClose !== false)
const handleHide = () => {
if (modal() && allowClose()) {
hideModal()
props.onClose && props.onClose()
} else {
redirectPage(router, 'home')
}
hideModal()
}
useEscKeyDownHandler(handleHide)
@ -45,22 +49,20 @@ export const Modal = (props: Props) => {
onClick={(event) => event.stopPropagation()}
>
{props.children}
<Show when={allowClose()}>
<div class={styles.close} onClick={handleHide}>
<svg
class={styles.icon}
width="16"
height="18"
viewBox="0 0 16 18"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.99987 7.52552L14.1871 0.92334L15.9548 2.80968L9.76764 9.41185L15.9548 16.014L14.1871 17.9004L7.99987 11.2982L1.81269 17.9004L0.0449219 16.014L6.23211 9.41185L0.0449225 2.80968L1.81269 0.92334L7.99987 7.52552Z"
fill="currentColor"
/>
</svg>
</div>
</Show>
<div class={styles.close} onClick={handleHide}>
<svg
class={styles.icon}
width="16"
height="18"
viewBox="0 0 16 18"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.99987 7.52552L14.1871 0.92334L15.9548 2.80968L9.76764 9.41185L15.9548 16.014L14.1871 17.9004L7.99987 11.2982L1.81269 17.9004L0.0449219 16.014L6.23211 9.41185L0.0449225 2.80968L1.81269 0.92334L7.99987 7.52552Z"
fill="currentColor"
/>
</svg>
</div>
</div>
</div>
</Show>

View File

@ -18,6 +18,9 @@ import stylesTopic from '../Feed/CardTopic.module.scss'
import stylesBeside from '../../components/Feed/Beside.module.scss'
import { CommentDate } from '../Article/CommentDate'
import { Loading } from '../_shared/Loading'
import { ConditionalWrapper } from '../_shared/ConditionalWrapper'
import { AuthGuard } from '../AuthGuard'
import { useSession } from '../../context/session'
export const FEED_PAGE_SIZE = 20
@ -37,9 +40,17 @@ const getOrderBy = (by: FeedSearchParams['by']) => {
return ''
}
const routesWithAuthGuard = new Set([
'feedMy',
'feedNotifications',
'feedBookmarks',
'feedCollaborations',
'feedDiscussions'
])
export const FeedView = () => {
const { t } = useLocalize()
const { page, searchParams } = useRouter<FeedSearchParams>()
const { isAuthenticated } = useSession()
const [isLoading, setIsLoading] = createSignal(false)
// state
@ -69,7 +80,6 @@ export const FeedView = () => {
{ defer: true }
)
)
const loadFeedShouts = () => {
const options: LoadShoutsOptions = {
limit: FEED_PAGE_SIZE,
@ -82,7 +92,7 @@ export const FeedView = () => {
options.order_by = orderBy
}
if (page().route === 'feedMy') {
if (routesWithAuthGuard.has(page().route) && isAuthenticated()) {
return loadMyFeed(options)
}
@ -116,155 +126,157 @@ export const FeedView = () => {
return (
<div>
<div class="wide-container feed">
<div class="row">
<div class={clsx('col-md-5 col-xl-4', styles.feedNavigation)}>
<Sidebar authors={sortedAuthors()} />
</div>
<AuthGuard disabled={!routesWithAuthGuard.has(page().route)}>
<div class="wide-container feed">
<div class="row">
<div class={clsx('col-md-5 col-xl-4', styles.feedNavigation)}>
<Sidebar authors={sortedAuthors()} />
</div>
<div class="col-md-12 offset-xl-1">
<ul class={clsx(styles.feedFilter, 'view-switcher')}>
<li
class={clsx({
'view-switcher__item--selected':
searchParams().by === 'publish_date' || !searchParams().by
})}
>
<a href={getPagePath(router, page().route)}>{t('Recent')}</a>
</li>
{/*<li>*/}
{/* <a href="/feed/?by=views">{t('Most read')}</a>*/}
{/*</li>*/}
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'rating'
})}
>
<a href={`${getPagePath(router, page().route)}?by=rating`}>{t('Top rated')}</a>
</li>
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'last_comment'
})}
>
<a href={`${getPagePath(router, page().route)}?by=last_comment`}>{t('Most commented')}</a>
</li>
</ul>
<Show when={!isLoading()} fallback={<Loading />}>
<Show when={sortedArticles().length > 0}>
<For each={sortedArticles().slice(0, 4)}>
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
</For>
<div class={styles.asideSection}>
<div class={stylesBeside.besideColumnTitle}>
<h4>{t('Popular authors')}</h4>
<a href="/authors">
{t('All authors')}
<Icon name="arrow-right" class={stylesBeside.icon} />
</a>
</div>
<ul class={stylesBeside.besideColumn}>
<For each={topAuthors().slice(0, 5)}>
{(author) => (
<li>
<AuthorCard
author={author}
hideWriteButton={true}
hasLink={true}
truncateBio={true}
isTextButton={true}
/>
</li>
)}
</For>
</ul>
</div>
<For each={sortedArticles().slice(4)}>
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
</For>
</Show>
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
</Show>
</Show>
</div>
<aside class={clsx('col-md-7 col-xl-6 offset-xl-1', styles.feedAside)}>
<section class={styles.asideSection}>
<h4>{t('Comments')}</h4>
<For each={topComments()}>
{(comment) => {
return (
<div class={styles.comment}>
<div class={clsx('text-truncate', styles.commentBody)}>
<a
href={`${getPagePath(router, 'article', {
slug: comment.shout.slug
})}?commentId=${comment.id}`}
innerHTML={comment.body}
/>
</div>
<div class={styles.commentDetails}>
<AuthorCard
author={comment.createdBy as Author}
isFeedMode={true}
hideWriteButton={true}
hideFollow={true}
hasLink={true}
/>
<CommentDate comment={comment} isShort={true} isLastInRow={true} />
</div>
<div class={clsx('text-truncate', styles.commentArticleTitle)}>
<a href={`/${comment.shout.slug}`}>{comment.shout.title}</a>
</div>
</div>
)
}}
</For>
</section>
<Show when={topTopics().length > 0}>
<section class={styles.asideSection}>
<h4>{t('Hot topics')}</h4>
<For each={topTopics().slice(0, 7)}>
{(topic) => (
<span class={clsx(stylesTopic.shoutTopic, styles.topic)}>
<a href={`/topic/${topic.slug}`}>{topic.title}</a>{' '}
</span>
)}
</For>
</section>
</Show>
<section class={clsx(styles.asideSection, styles.pinnedLinks)}>
<h4>{t('Knowledge base')}</h4>
<ul class="nodash">
<li>
<a href={getPagePath(router, 'guide')}>Как устроен Дискурс</a>
<div class="col-md-12 offset-xl-1">
<ul class={clsx(styles.feedFilter, 'view-switcher')}>
<li
class={clsx({
'view-switcher__item--selected':
searchParams().by === 'publish_date' || !searchParams().by
})}
>
<a href={getPagePath(router, page().route)}>{t('Recent')}</a>
</li>
<li>
<a href="/how-to-write-a-good-article">Как создать хороший текст</a>
{/*<li>*/}
{/* <a href="/feed/?by=views">{t('Most read')}</a>*/}
{/*</li>*/}
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'rating'
})}
>
<a href={`${getPagePath(router, page().route)}?by=rating`}>{t('Top rated')}</a>
</li>
<li>
<a href="#">Правила конструктивных дискуссий</a>
</li>
<li>
<a href={getPagePath(router, 'principles')}>Принципы сообщества</a>
<li
class={clsx({
'view-switcher__item--selected': searchParams().by === 'last_comment'
})}
>
<a href={`${getPagePath(router, page().route)}?by=last_comment`}>{t('Most commented')}</a>
</li>
</ul>
</section>
</aside>
<Show when={!isLoading()} fallback={<Loading />}>
<Show when={sortedArticles().length > 0}>
<For each={sortedArticles().slice(0, 4)}>
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
</For>
<div class={styles.asideSection}>
<div class={stylesBeside.besideColumnTitle}>
<h4>{t('Popular authors')}</h4>
<a href="/authors">
{t('All authors')}
<Icon name="arrow-right" class={stylesBeside.icon} />
</a>
</div>
<ul class={stylesBeside.besideColumn}>
<For each={topAuthors().slice(0, 5)}>
{(author) => (
<li>
<AuthorCard
author={author}
hideWriteButton={true}
hasLink={true}
truncateBio={true}
isTextButton={true}
/>
</li>
)}
</For>
</ul>
</div>
<For each={sortedArticles().slice(4)}>
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
</For>
</Show>
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
</Show>
</Show>
</div>
<aside class={clsx('col-md-7 col-xl-6 offset-xl-1', styles.feedAside)}>
<section class={styles.asideSection}>
<h4>{t('Comments')}</h4>
<For each={topComments()}>
{(comment) => {
return (
<div class={styles.comment}>
<div class={clsx('text-truncate', styles.commentBody)}>
<a
href={`${getPagePath(router, 'article', {
slug: comment.shout.slug
})}?commentId=${comment.id}`}
innerHTML={comment.body}
/>
</div>
<div class={styles.commentDetails}>
<AuthorCard
author={comment.createdBy as Author}
isFeedMode={true}
hideWriteButton={true}
hideFollow={true}
hasLink={true}
/>
<CommentDate comment={comment} isShort={true} isLastInRow={true} />
</div>
<div class={clsx('text-truncate', styles.commentArticleTitle)}>
<a href={`/${comment.shout.slug}`}>{comment.shout.title}</a>
</div>
</div>
)
}}
</For>
</section>
<Show when={topTopics().length > 0}>
<section class={styles.asideSection}>
<h4>{t('Hot topics')}</h4>
<For each={topTopics().slice(0, 7)}>
{(topic) => (
<span class={clsx(stylesTopic.shoutTopic, styles.topic)}>
<a href={`/topic/${topic.slug}`}>{topic.title}</a>{' '}
</span>
)}
</For>
</section>
</Show>
<section class={clsx(styles.asideSection, styles.pinnedLinks)}>
<h4>{t('Knowledge base')}</h4>
<ul class="nodash">
<li>
<a href={getPagePath(router, 'guide')}>Как устроен Дискурс</a>
</li>
<li>
<a href="/how-to-write-a-good-article">Как создать хороший текст</a>
</li>
<li>
<a href="#">Правила конструктивных дискуссий</a>
</li>
<li>
<a href={getPagePath(router, 'principles')}>Принципы сообщества</a>
</li>
</ul>
</section>
</aside>
</div>
</div>
</div>
</AuthGuard>
</div>
)
}

View File

@ -39,8 +39,6 @@ export const GrowingTextarea = (props: Props) => {
}
}
console.log('!!! initialValue:', props.initialValue)
return (
<div
class={clsx(styles.GrowingTextarea, {