Implement auth modal calling on required actions & fix minor ui bugs. (#108)
* fix views & date layout * handle auth modal calling on required actions & fix minor ui bugs * fix eslint errors * refactor auth modals for non sessioned & implement callback triggering after sign in * refactor handlers with requireAuth
This commit is contained in:
parent
06c3740db2
commit
778e8e8c43
19
package-lock.json
generated
19
package-lock.json
generated
|
@ -89,6 +89,7 @@
|
|||
"eslint-config-stylelint": "18.0.0",
|
||||
"eslint-import-resolver-typescript": "3.5.5",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jest": "27.2.1",
|
||||
"eslint-plugin-jsx-a11y": "6.7.1",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-solid": "0.12.1",
|
||||
|
@ -148,7 +149,7 @@
|
|||
"uniqolor": "1.1.0",
|
||||
"unique-names-generator": "4.7.1",
|
||||
"uuid": "9.0.0",
|
||||
"vite": "4.3.5",
|
||||
"vite": "4.3.9",
|
||||
"vite-plugin-sass-dts": "1.3.5",
|
||||
"vite-plugin-solid": "2.7.0",
|
||||
"vite-plugin-ssr": "0.4.123",
|
||||
|
@ -9447,8 +9448,6 @@
|
|||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz",
|
||||
"integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
},
|
||||
|
@ -19958,9 +19957,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.5.tgz",
|
||||
"integrity": "sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==",
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
|
||||
"integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
|
@ -27778,8 +27777,6 @@
|
|||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz",
|
||||
"integrity": "sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
|
@ -35451,9 +35448,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"vite": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.5.tgz",
|
||||
"integrity": "sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==",
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
|
||||
"integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esbuild": "^0.17.5",
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
"eslint-config-stylelint": "18.0.0",
|
||||
"eslint-import-resolver-typescript": "3.5.5",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jest": "27.2.1",
|
||||
"eslint-plugin-jsx-a11y": "6.7.1",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-solid": "0.12.1",
|
||||
|
@ -168,7 +169,7 @@
|
|||
"uniqolor": "1.1.0",
|
||||
"unique-names-generator": "4.7.1",
|
||||
"uuid": "9.0.0",
|
||||
"vite": "4.3.5",
|
||||
"vite": "4.3.9",
|
||||
"vite-plugin-sass-dts": "1.3.5",
|
||||
"vite-plugin-solid": "2.7.0",
|
||||
"vite-plugin-ssr": "0.4.123",
|
||||
|
|
|
@ -56,6 +56,11 @@
|
|||
"Create Chat": "Create Chat",
|
||||
"Create Group": "Create a group",
|
||||
"Create account": "Create an account",
|
||||
"Create account from subscribe": "Create an account to subscribe to new publications",
|
||||
"Create account from discussions": "Create an account to participate in discussions",
|
||||
"Create account from vote": "Create an account to vote",
|
||||
"Create account from bookmark": "Create an account to add to your bookmarks",
|
||||
"Create account from follow": "Create an account to subscribe",
|
||||
"Create post": "Create post",
|
||||
"Date of Birth": "Date of Birth",
|
||||
"Delete": "Delete",
|
||||
|
@ -74,6 +79,11 @@
|
|||
"Enter URL address": "Enter URL address",
|
||||
"Enter text": "Enter text",
|
||||
"Enter the Discours": "Enter the Discours",
|
||||
"Enter the Discours from subscribe": "Sign in to subscribe to new publications",
|
||||
"Enter the Discours from discussions": "Sign in to participate in the discussions",
|
||||
"Enter the Discours from vote": "Sign in to vote",
|
||||
"Enter the Discours from bookmark": "Sign in to add to bookmarks",
|
||||
"Enter the Discours from follow": "Sign in to follow",
|
||||
"Enter the code or click the link from email to confirm": "Enter the code from the email or follow the link in the email to confirm registration",
|
||||
"Enter your new password": "Enter your new password",
|
||||
"Error": "Error",
|
||||
|
|
|
@ -58,6 +58,11 @@
|
|||
"Create Chat": "Создать чат",
|
||||
"Create Group": "Создать группу",
|
||||
"Create account": "Создать аккаунт",
|
||||
"Create account from subscribe": "Создайте аккаунт для подписки на новые публикации",
|
||||
"Create account from discussions": "Создайте аккаунт для участия в дискуссиях",
|
||||
"Create account from vote": "Создайте аккаунт, чтобы голосовать",
|
||||
"Create account from bookmark": "Создайте аккаунт, чтобы добавить в закладки",
|
||||
"Create account from follow": "Создайте аккаунт, чтобы подписаться",
|
||||
"Create post": "Создать публикацию",
|
||||
"Date of Birth": "Дата рождения",
|
||||
"Delete": "Удалить",
|
||||
|
@ -77,6 +82,11 @@
|
|||
"Enter URL address": "Введите адрес ссылки",
|
||||
"Enter text": "Введите текст",
|
||||
"Enter the Discours": "Войти в Дискурс",
|
||||
"Enter the Discours from subscribe": "Войдите для подписки на новые публикации",
|
||||
"Enter the Discours from discussions": "Войдите для участия в дискуссиях",
|
||||
"Enter the Discours from vote": "Войдите, чтобы голосовать",
|
||||
"Enter the Discours from bookmark": "Войдите, чтобы добавить в закладки",
|
||||
"Enter the Discours from follow": "Войдите, чтобы подписаться",
|
||||
"Enter the code or click the link from email to confirm": "Введите код из письма или пройдите по ссылке в письме для подтверждения регистрации",
|
||||
"Enter your new password": "Введите новый пароль",
|
||||
"Error": "Ошибка",
|
||||
|
|
|
@ -237,6 +237,7 @@ img {
|
|||
margin-right: 0;
|
||||
margin-left: auto;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
|
||||
.icon {
|
||||
opacity: 0.4;
|
||||
|
@ -248,11 +249,18 @@ img {
|
|||
}
|
||||
}
|
||||
|
||||
.shoutStatsItemViews {
|
||||
margin-left: 2rem;
|
||||
margin-right: 0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.shoutStatsItemAdditionalDataItem {
|
||||
font-weight: normal;
|
||||
display: inline-block;
|
||||
margin-left: 2rem;
|
||||
margin-right: 0;
|
||||
cursor: default;
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
&:first-child {
|
||||
|
|
|
@ -62,7 +62,11 @@ const MediaView = (props: { media: MediaItem; kind: Shout['layout'] }) => {
|
|||
|
||||
export const FullArticle = (props: ArticleProps) => {
|
||||
const { t } = useLocalize()
|
||||
const { user, isAuthenticated } = useSession()
|
||||
const {
|
||||
user,
|
||||
isAuthenticated,
|
||||
actions: { requireAuthentication }
|
||||
} = useSession()
|
||||
const [isReactionsLoaded, setIsReactionsLoaded] = createSignal(false)
|
||||
const formattedDate = createMemo(() => formatDate(new Date(props.article.createdAt)))
|
||||
|
||||
|
@ -81,10 +85,12 @@ export const FullArticle = (props: ArticleProps) => {
|
|||
})
|
||||
|
||||
const canEdit = () => props.article.authors?.some((a) => a.slug === user()?.slug)
|
||||
// eslint-disable-next-line unicorn/consistent-function-scoping
|
||||
|
||||
const handleBookmarkButtonClick = (ev) => {
|
||||
requireAuthentication(() => {
|
||||
// TODO: implement bookmark clicked
|
||||
ev.preventDefault()
|
||||
}, 'bookmark')
|
||||
}
|
||||
|
||||
const body = createMemo(() => props.article.body)
|
||||
|
@ -222,12 +228,6 @@ export const FullArticle = (props: ArticleProps) => {
|
|||
<ShoutRatingControl shout={props.article} class={styles.ratingControl} />
|
||||
</div>
|
||||
|
||||
<Show when={props.article.stat?.viewed}>
|
||||
<div class={clsx(styles.shoutStatsItem)}>
|
||||
<Icon name="eye" class={clsx(styles.icon, styles.iconEye)} />
|
||||
{props.article.stat?.viewed}
|
||||
</div>
|
||||
</Show>
|
||||
<Popover content={t('Comment')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
<div class={styles.shoutStatsItem} ref={triggerRef} onClick={scrollToComments}>
|
||||
|
@ -280,6 +280,12 @@ export const FullArticle = (props: ArticleProps) => {
|
|||
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemAdditionalDataItem)}>
|
||||
{formattedDate()}
|
||||
</div>
|
||||
<Show when={props.article.stat?.viewed}>
|
||||
<div class={clsx(styles.shoutStatsItem, styles.shoutStatsItemViews)}>
|
||||
<Icon name="eye" class={clsx(styles.icon, styles.iconEye)} />
|
||||
{props.article.stat?.viewed}
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
<div class={styles.help}>
|
||||
|
|
|
@ -16,7 +16,10 @@ interface ShoutRatingControlProps {
|
|||
|
||||
export const ShoutRatingControl = (props: ShoutRatingControlProps) => {
|
||||
const { t } = useLocalize()
|
||||
const { user } = useSession()
|
||||
const {
|
||||
user,
|
||||
actions: { requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const {
|
||||
reactionEntities,
|
||||
|
@ -57,6 +60,7 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => {
|
|||
}
|
||||
|
||||
const handleRatingChange = async (isUpvote: boolean) => {
|
||||
requireAuthentication(async () => {
|
||||
if (isUpvoted()) {
|
||||
await deleteShoutReaction(ReactionKind.Like)
|
||||
} else if (isDownvoted()) {
|
||||
|
@ -72,6 +76,7 @@ export const ShoutRatingControl = (props: ShoutRatingControlProps) => {
|
|||
loadReactionsBy({
|
||||
by: { shout: props.shout.slug }
|
||||
})
|
||||
}, 'vote')
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -13,6 +13,7 @@ import { FollowingEntity } from '../../graphql/types.gen'
|
|||
import { router, useRouter } from '../../stores/router'
|
||||
import { openPage } from '@nanostores/router'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { init } from 'i18next'
|
||||
|
||||
interface AuthorCardProps {
|
||||
caption?: string
|
||||
|
@ -40,7 +41,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
|||
const {
|
||||
session,
|
||||
isSessionLoaded,
|
||||
actions: { loadSession }
|
||||
actions: { loadSession, requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
||||
|
@ -77,9 +78,18 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
|||
// TODO: reimplement AuthorCard
|
||||
const { changeSearchParam } = useRouter()
|
||||
const initChat = () => {
|
||||
requireAuthentication(() => {
|
||||
openPage(router, `inbox`)
|
||||
changeSearchParam('initChat', `${props.author.id}`)
|
||||
}, 'discussions')
|
||||
}
|
||||
|
||||
const handleSubscribe = () => {
|
||||
requireAuthentication(() => {
|
||||
subscribe(true)
|
||||
}, 'subscribe')
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={clsx(styles.author, props.class)}
|
||||
|
@ -133,7 +143,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
|||
when={subscribed()}
|
||||
fallback={
|
||||
<button
|
||||
onClick={() => subscribe(true)}
|
||||
onClick={handleSubscribe}
|
||||
class={clsx('button', styles.button)}
|
||||
classList={{
|
||||
[styles.buttonSubscribe]: !props.isAuthorsList && !props.isTextButton,
|
||||
|
|
|
@ -30,7 +30,7 @@ export const Beside = (props: BesideProps) => {
|
|||
<Show when={!!props.beside?.slug && props.values?.length > 0}>
|
||||
<div class="floor floor--9">
|
||||
<div class="wide-container">
|
||||
<div class="row">
|
||||
<div class="row justify-content-between">
|
||||
<Show when={!!props.values}>
|
||||
<div
|
||||
class={clsx(
|
||||
|
@ -102,7 +102,7 @@ export const Beside = (props: BesideProps) => {
|
|||
</ul>
|
||||
</div>
|
||||
</Show>
|
||||
<div class={clsx('col-md-16', styles.shoutCardContainer)}>
|
||||
<div class={clsx('col-md-14', styles.shoutCardContainer)}>
|
||||
<ArticleCard
|
||||
article={props.beside}
|
||||
settings={{ isBigTitle: true, isBeside: true, nodate: props.nodate }}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { hideModal } from '../../../stores/ui'
|
|||
import { useSession } from '../../../context/session'
|
||||
import { signSendLink } from '../../../stores/auth'
|
||||
import { isValidEmail } from '../../../utils/validators'
|
||||
import { generateModalTitleFromSource } from '../../../utils/custom-i18n'
|
||||
|
||||
import { useSnackbar } from '../../../context/snackbar'
|
||||
import { useLocalize } from '../../../context/localize'
|
||||
|
@ -117,7 +118,7 @@ export const LoginForm = () => {
|
|||
return (
|
||||
<form onSubmit={handleSubmit} class={styles.authForm}>
|
||||
<div>
|
||||
<h4>{t('Enter the Discours')}</h4>
|
||||
<h4>{generateModalTitleFromSource('login')}</h4>
|
||||
<Show when={submitError()}>
|
||||
<div class={styles.authInfo}>
|
||||
<div class={styles.warn}>{submitError()}</div>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { checkEmail, useEmailChecks } from '../../../stores/emailChecks'
|
|||
import { register } from '../../../stores/auth'
|
||||
import { useLocalize } from '../../../context/localize'
|
||||
import { isValidEmail } from '../../../utils/validators'
|
||||
import { generateModalTitleFromSource } from '../../../utils/custom-i18n'
|
||||
|
||||
type FormFields = {
|
||||
name: string
|
||||
|
@ -136,7 +137,7 @@ export const RegisterForm = () => {
|
|||
<Show when={!isSuccess()}>
|
||||
<form onSubmit={handleSubmit} class={styles.authForm}>
|
||||
<div>
|
||||
<h4>{t('Create account')}</h4>
|
||||
<h4>{generateModalTitleFromSource('register')}</h4>
|
||||
<Show when={submitError()}>
|
||||
<div class={styles.authInfo}>
|
||||
<ul>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useRouter } from '../../../stores/router'
|
|||
import { clsx } from 'clsx'
|
||||
import styles from './AuthModal.module.scss'
|
||||
import { LoginForm } from './LoginForm'
|
||||
import { isMobile } from '../../../utils/media-query'
|
||||
import { RegisterForm } from './RegisterForm'
|
||||
import { ForgotPasswordForm } from './ForgotPasswordForm'
|
||||
import { EmailConfirm } from './EmailConfirm'
|
||||
|
@ -28,7 +29,7 @@ export const AuthModal = () => {
|
|||
})
|
||||
|
||||
createEffect((oldMode) => {
|
||||
if (oldMode !== mode()) {
|
||||
if (oldMode !== mode() && !isMobile()) {
|
||||
rootRef?.querySelector('input')?.focus()
|
||||
}
|
||||
}, null)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
export type AuthModalMode = 'login' | 'register' | 'confirm-email' | 'forgot-password'
|
||||
export type AuthModalSource = 'discussions' | 'vote' | 'subscribe' | 'bookmark' | 'follow'
|
||||
|
||||
export type AuthModalSearchParams = {
|
||||
mode: AuthModalMode
|
||||
source?: AuthModalSource
|
||||
}
|
||||
|
||||
export type ConfirmEmailSearchParams = {
|
||||
|
|
|
@ -31,7 +31,7 @@ export const TopicCard = (props: TopicProps) => {
|
|||
const {
|
||||
session,
|
||||
isSessionLoaded,
|
||||
actions: { loadSession }
|
||||
actions: { loadSession, requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
||||
|
@ -55,6 +55,12 @@ export const TopicCard = (props: TopicProps) => {
|
|||
setIsSubscribing(false)
|
||||
}
|
||||
|
||||
const handleSubscribe = () => {
|
||||
requireAuthentication(() => {
|
||||
subscribe(!subscribed())
|
||||
}, 'subscribe')
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={styles.topicContainer}>
|
||||
<div
|
||||
|
@ -100,7 +106,7 @@ export const TopicCard = (props: TopicProps) => {
|
|||
<ShowOnlyOnClient>
|
||||
<Show when={isSessionLoaded()}>
|
||||
<button
|
||||
onClick={() => subscribe(!subscribed())}
|
||||
onClick={handleSubscribe}
|
||||
class="button--light button--subscribe-topic"
|
||||
classList={{
|
||||
[styles.isSubscribing]: isSubscribing(),
|
||||
|
|
|
@ -13,27 +13,35 @@ type Props = {
|
|||
}
|
||||
|
||||
export const FullTopic = (props: Props) => {
|
||||
const { session } = useSession()
|
||||
const {
|
||||
session,
|
||||
actions: { requireAuthentication }
|
||||
} = useSession()
|
||||
const { t } = useLocalize()
|
||||
const subscribed = createMemo(() => session()?.news?.topics?.includes(props.topic?.slug))
|
||||
|
||||
const handleSubscribe = (isFollowed: boolean) => {
|
||||
requireAuthentication(() => {
|
||||
if (isFollowed) {
|
||||
unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug })
|
||||
} else {
|
||||
follow({ what: FollowingEntity.Topic, slug: props.topic.slug })
|
||||
}
|
||||
}, 'follow')
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={clsx(styles.topicHeader, 'col-md-16 col-lg-12 offset-md-4 offset-lg-6')}>
|
||||
<h1>#{props.topic.title}</h1>
|
||||
<p>{props.topic.body}</p>
|
||||
<div class={clsx(styles.topicActions)}>
|
||||
<Show when={!subscribed()}>
|
||||
<button
|
||||
onClick={() => follow({ what: FollowingEntity.Topic, slug: props.topic.slug })}
|
||||
class="button"
|
||||
>
|
||||
<button onClick={() => handleSubscribe(false)} class="button">
|
||||
{t('Follow the topic')}
|
||||
</button>
|
||||
</Show>
|
||||
<Show when={subscribed()}>
|
||||
<button
|
||||
onClick={() => unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug })}
|
||||
class="button"
|
||||
>
|
||||
<button onClick={() => handleSubscribe(true)} class="button">
|
||||
{t('Unfollow the topic')}
|
||||
</button>
|
||||
</Show>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import type { Accessor, JSX, Resource } from 'solid-js'
|
||||
import { Accessor, JSX, Resource, createEffect } from 'solid-js'
|
||||
import { createContext, createMemo, createResource, createSignal, onMount, useContext } from 'solid-js'
|
||||
import type { AuthResult, User } from '../graphql/types.gen'
|
||||
import { apiClient } from '../utils/apiClient'
|
||||
import { resetToken, setToken } from '../graphql/privateGraphQLClient'
|
||||
import { useSnackbar } from './snackbar'
|
||||
import { useLocalize } from './localize'
|
||||
import { showModal } from '../stores/ui'
|
||||
import type { AuthModalSource } from '../components/Nav/AuthModal/types'
|
||||
|
||||
type SessionContextType = {
|
||||
session: Resource<AuthResult>
|
||||
|
@ -13,6 +15,10 @@ type SessionContextType = {
|
|||
isAuthenticated: Accessor<boolean>
|
||||
actions: {
|
||||
loadSession: () => AuthResult | Promise<AuthResult>
|
||||
requireAuthentication: (
|
||||
callback: (() => Promise<void>) | (() => void),
|
||||
modalSource: AuthModalSource
|
||||
) => void
|
||||
signIn: ({ email, password }: { email: string; password: string }) => Promise<void>
|
||||
signOut: () => Promise<void>
|
||||
confirmEmail: (token: string) => Promise<void>
|
||||
|
@ -65,6 +71,28 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
console.debug('signed in')
|
||||
}
|
||||
|
||||
const [isAuthWithCallback, setIsAuthWithCallback] = createSignal(null)
|
||||
|
||||
const requireAuthentication = (callback: () => void, modalSource: AuthModalSource) => {
|
||||
setIsAuthWithCallback(() => callback)
|
||||
|
||||
if (!isAuthenticated()) {
|
||||
showModal('auth', modalSource)
|
||||
}
|
||||
}
|
||||
|
||||
createEffect(async () => {
|
||||
if (isAuthWithCallback()) {
|
||||
const sessionProof = await session()
|
||||
|
||||
if (sessionProof) {
|
||||
await isAuthWithCallback()()
|
||||
|
||||
setIsAuthWithCallback(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const signOut = async () => {
|
||||
// TODO: call backend to revoke token
|
||||
mutate(null)
|
||||
|
@ -80,6 +108,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
|
||||
const actions = {
|
||||
loadSession,
|
||||
requireAuthentication,
|
||||
signIn,
|
||||
signOut,
|
||||
confirmEmail
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import { createSignal } from 'solid-js'
|
||||
import { useRouter } from './router'
|
||||
import type { AuthModalSearchParams, ConfirmEmailSearchParams } from '../components/Nav/AuthModal/types'
|
||||
import type {
|
||||
AuthModalSearchParams,
|
||||
AuthModalSource,
|
||||
ConfirmEmailSearchParams
|
||||
} from '../components/Nav/AuthModal/types'
|
||||
import type { RootSearchParams } from '../pages/types'
|
||||
|
||||
export type ModalType =
|
||||
|
@ -36,14 +40,20 @@ const [modal, setModal] = createSignal<ModalType | null>(null)
|
|||
|
||||
const [warnings, setWarnings] = createSignal<Warning[]>([])
|
||||
|
||||
export const showModal = (modalType: ModalType) => setModal(modalType)
|
||||
|
||||
// TODO: find a better solution
|
||||
export const hideModal = () => {
|
||||
const { searchParams, changeSearchParam } = useRouter<
|
||||
AuthModalSearchParams & ConfirmEmailSearchParams & RootSearchParams
|
||||
>()
|
||||
|
||||
export const showModal = (modalType: ModalType, modalSource?: AuthModalSource) => {
|
||||
if (modalSource) {
|
||||
changeSearchParam('source', modalSource)
|
||||
}
|
||||
|
||||
setModal(modalType)
|
||||
}
|
||||
|
||||
// TODO: find a better solution
|
||||
export const hideModal = () => {
|
||||
if (searchParams().modal === 'auth') {
|
||||
if (searchParams().mode === 'confirm-email') {
|
||||
changeSearchParam('token', null, true)
|
||||
|
@ -52,6 +62,7 @@ export const hideModal = () => {
|
|||
}
|
||||
|
||||
changeSearchParam('modal', null, true)
|
||||
changeSearchParam('source', null, true)
|
||||
|
||||
setModal(null)
|
||||
}
|
||||
|
|
16
src/utils/custom-i18n.ts
Normal file
16
src/utils/custom-i18n.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { useRouter } from '../stores/router'
|
||||
import type { AuthModalSearchParams } from '../components/Nav/AuthModal/types'
|
||||
import { useLocalize } from '../context/localize'
|
||||
|
||||
export const generateModalTitleFromSource = (modalType: 'login' | 'register') => {
|
||||
const { searchParams } = useRouter<AuthModalSearchParams>()
|
||||
const { t } = useLocalize()
|
||||
|
||||
const { source } = searchParams()
|
||||
|
||||
let title = modalType === 'login' ? 'Enter the Discours' : 'Create account'
|
||||
|
||||
if (source) title = `${title} from ${source}`
|
||||
|
||||
return t(title)
|
||||
}
|
3
src/utils/media-query.ts
Normal file
3
src/utils/media-query.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { createMediaQuery } from '@solid-primitives/media'
|
||||
|
||||
export const isMobile = createMediaQuery('(max-width: 767px)')
|
Loading…
Reference in New Issue
Block a user