From 5e18abba2a118671ef477af7280882f0b06cfa8d Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:38:22 +0300 Subject: [PATCH] Add AuthWrapper (#227) * Add AuthWrapper --- .../AuthGuard/AuthGuard.module.scss | 3 + src/components/AuthGuard/AuthGuard.tsx | 22 ++ src/components/AuthGuard/index.ts | 1 + src/components/Nav/AuthModal/types.ts | 9 +- src/components/Nav/Header/Header.tsx | 8 +- src/components/Nav/HeaderAuth.tsx | 5 +- src/components/Nav/Modal/Modal.tsx | 43 +-- .../ProfileSubscriptions.module.scss | 3 + .../ProfileSubscriptions.tsx | 140 +++++++++ .../Views/ProfileSubscriptions/index.ts | 1 + src/pages/create.page.tsx | 75 ++--- src/pages/edit.page.tsx | 24 +- src/pages/profile/profileSecurity.page.tsx | 217 ++++++------- src/pages/profile/profileSettings.page.tsx | 295 +++++++++--------- .../profile/profileSubscriptions.page.tsx | 139 +-------- src/stores/ui.ts | 2 +- 16 files changed, 521 insertions(+), 466 deletions(-) create mode 100644 src/components/AuthGuard/AuthGuard.module.scss create mode 100644 src/components/AuthGuard/AuthGuard.tsx create mode 100644 src/components/AuthGuard/index.ts create mode 100644 src/components/Views/ProfileSubscriptions/ProfileSubscriptions.module.scss create mode 100644 src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx create mode 100644 src/components/Views/ProfileSubscriptions/index.ts diff --git a/src/components/AuthGuard/AuthGuard.module.scss b/src/components/AuthGuard/AuthGuard.module.scss new file mode 100644 index 00000000..f8936ffe --- /dev/null +++ b/src/components/AuthGuard/AuthGuard.module.scss @@ -0,0 +1,3 @@ +.AuthGuard { + min-height: 60vh; +} diff --git a/src/components/AuthGuard/AuthGuard.tsx b/src/components/AuthGuard/AuthGuard.tsx new file mode 100644 index 00000000..9cc6b842 --- /dev/null +++ b/src/components/AuthGuard/AuthGuard.tsx @@ -0,0 +1,22 @@ +import { createEffect, JSX, Show } from 'solid-js' +import { useSession } from '../../context/session' +import { hideModal, showModal } from '../../stores/ui' + +type Props = { + children: JSX.Element +} + +export const AuthGuard = (props: Props) => { + const { isAuthenticated, isSessionLoaded } = useSession() + createEffect(() => { + if (isSessionLoaded()) { + if (isAuthenticated()) { + hideModal() + } else { + showModal('auth', 'authguard') + } + } + }) + + return {props.children} +} diff --git a/src/components/AuthGuard/index.ts b/src/components/AuthGuard/index.ts new file mode 100644 index 00000000..80b0b6d6 --- /dev/null +++ b/src/components/AuthGuard/index.ts @@ -0,0 +1 @@ +export { AuthGuard } from './AuthGuard' diff --git a/src/components/Nav/AuthModal/types.ts b/src/components/Nav/AuthModal/types.ts index ea233cf1..905b77cf 100644 --- a/src/components/Nav/AuthModal/types.ts +++ b/src/components/Nav/AuthModal/types.ts @@ -1,5 +1,12 @@ export type AuthModalMode = 'login' | 'register' | 'confirm-email' | 'forgot-password' -export type AuthModalSource = 'discussions' | 'vote' | 'subscribe' | 'bookmark' | 'follow' | 'create' +export type AuthModalSource = + | 'discussions' + | 'vote' + | 'subscribe' + | 'bookmark' + | 'follow' + | 'create' + | 'authguard' export type AuthModalSearchParams = { mode: AuthModalMode diff --git a/src/components/Nav/Header/Header.tsx b/src/components/Nav/Header/Header.tsx index f3e8585f..e58c08ef 100644 --- a/src/components/Nav/Header/Header.tsx +++ b/src/components/Nav/Header/Header.tsx @@ -145,6 +145,7 @@ export const Header = (props: Props) => { const topics = await apiClient.getRandomTopics({ amount: RANDOM_TOPICS_COUNT }) setRandomTopics(topics) }) + return (
{ [styles.headerWithTitle]: Boolean(props.title) }} > - + diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index d0adffb3..a24e2132 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -107,10 +107,7 @@ export const HeaderAuth = (props: Props) => { return ( -
+
diff --git a/src/components/Nav/Modal/Modal.tsx b/src/components/Nav/Modal/Modal.tsx index 452f66cc..43868240 100644 --- a/src/components/Nav/Modal/Modal.tsx +++ b/src/components/Nav/Modal/Modal.tsx @@ -1,28 +1,27 @@ -import { createEffect, createSignal, Show } from 'solid-js' +import { createEffect, createMemo, createSignal, Show } from 'solid-js' import type { JSX } from 'solid-js' import { clsx } from 'clsx' - import { hideModal, useModalStore } from '../../../stores/ui' import { useEscKeyDownHandler } from '../../../utils/useEscKeyDownHandler' import styles from './Modal.module.scss' -interface ModalProps { +interface Props { name: string variant: 'narrow' | 'wide' children: JSX.Element onClose?: () => void noPadding?: boolean maxHeight?: boolean + allowClose?: boolean } -export const Modal = (props: ModalProps) => { +export const Modal = (props: Props) => { const { modal } = useModalStore() - const [visible, setVisible] = createSignal(false) - + const allowClose = createMemo(() => props.allowClose !== false) const handleHide = () => { - if (modal()) { + if (modal() && allowClose()) { hideModal() props.onClose && props.onClose() } @@ -46,20 +45,22 @@ export const Modal = (props: ModalProps) => { onClick={(event) => event.stopPropagation()} > {props.children} -
- - - -
+ +
+ + + +
+
diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.module.scss b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.module.scss new file mode 100644 index 00000000..4fe7ba54 --- /dev/null +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.module.scss @@ -0,0 +1,3 @@ +.ProfileSubscriptions { + display: block; +} diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx new file mode 100644 index 00000000..23c7f4f8 --- /dev/null +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -0,0 +1,140 @@ +import { clsx } from 'clsx' +// import styles from './ProfileSubscriptions.module.scss' +import { ProfileSettingsNavigation } from '../../Nav/ProfileSettingsNavigation' +import { createEffect, createSignal, For, onMount, Show } from 'solid-js' +import { Loading } from '../../_shared/Loading' +import { SearchField } from '../../_shared/SearchField' +import { isAuthor } from '../../../utils/isAuthor' +import { AuthorCard } from '../../Author/AuthorCard' +import { TopicCard } from '../../Topic/Card' +import { useLocalize } from '../../../context/localize' +import { useSession } from '../../../context/session' +import { Author, Topic } from '../../../graphql/types.gen' +import { SubscriptionFilter } from '../../../pages/types' +import { apiClient } from '../../../utils/apiClient' +import { dummyFilter } from '../../../utils/dummyFilter' +// TODO: refactor styles +import styles from '../../../pages/profile/Settings.module.scss' +import stylesSettings from '../../../styles/FeedSettings.module.scss' + +type Props = { + class?: string +} + +export const ProfileSubscriptions = (props: Props) => { + const { t, lang } = useLocalize() + const { user } = useSession() + const [following, setFollowing] = createSignal>([]) + const [filtered, setFiltered] = createSignal>([]) + const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') + const [searchQuery, setSearchQuery] = createSignal('') + + const fetchSubscriptions = async () => { + try { + const [getAuthors, getTopics] = await Promise.all([ + apiClient.getAuthorFollowingUsers({ slug: user().slug }), + apiClient.getAuthorFollowingTopics({ slug: user().slug }) + ]) + setFollowing([...getAuthors, ...getTopics]) + setFiltered([...getAuthors, ...getTopics]) + } catch (error) { + console.error('[fetchSubscriptions] :', error) + throw error + } + } + + createEffect(() => { + if (following()) { + if (subscriptionFilter() === 'users') { + setFiltered(following().filter((s) => 'name' in s)) + } else if (subscriptionFilter() === 'topics') { + setFiltered(following().filter((s) => 'title' in s)) + } else { + setFiltered(following()) + } + } + if (searchQuery()) { + setFiltered(dummyFilter(following(), searchQuery(), lang())) + } + }) + + onMount(async () => { + await fetchSubscriptions() + }) + + return ( +
+
+
+
+ +
+
+ +
+
+
+

{t('My subscriptions')}

+

{t('Here you can manage all your Discourse subscriptions')}

+ }> +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+ +
+ setSearchQuery(value)} + class={styles.searchField} + variant="bordered" + /> +
+ +
+ + {(followingItem) => ( +
+ {isAuthor(followingItem) ? ( + + ) : ( + + )} +
+ )} +
+
+
+
+
+
+
+
+ ) +} diff --git a/src/components/Views/ProfileSubscriptions/index.ts b/src/components/Views/ProfileSubscriptions/index.ts new file mode 100644 index 00000000..17849841 --- /dev/null +++ b/src/components/Views/ProfileSubscriptions/index.ts @@ -0,0 +1 @@ +export { ProfileSubscriptions } from './ProfileSubscriptions' diff --git a/src/pages/create.page.tsx b/src/pages/create.page.tsx index 69339410..1b9d115f 100644 --- a/src/pages/create.page.tsx +++ b/src/pages/create.page.tsx @@ -8,6 +8,7 @@ import { apiClient } from '../utils/apiClient' import { redirectPage } from '@nanostores/router' import { router } from '../stores/router' import { LayoutType } from './types' +import { AuthGuard } from '../components/AuthGuard' const handleCreate = async (layout: LayoutType) => { const shout = await apiClient.createArticle({ article: { layout: layout } }) @@ -20,42 +21,44 @@ export const CreatePage = () => { const { t } = useLocalize() return ( -
-

{t('Choose a post type')}

-
    -
  • -
    handleCreate('article')}> - -
    {t('article')}
    -
    -
  • -
  • -
    handleCreate('literature')}> - -
    {t('literature')}
    -
    -
  • -
  • -
    handleCreate('image')}> - -
    {t('images')}
    -
    -
  • -
  • -
    handleCreate('audio')}> - -
    {t('music')}
    -
    -
  • -
  • -
    handleCreate('video')}> - -
    {t('video')}
    -
    -
  • -
-
+ +
+

{t('Choose a post type')}

+
    +
  • +
    handleCreate('article')}> + +
    {t('article')}
    +
    +
  • +
  • +
    handleCreate('literature')}> + +
    {t('literature')}
    +
    +
  • +
  • +
    handleCreate('image')}> + +
    {t('images')}
    +
    +
  • +
  • +
    handleCreate('audio')}> + +
    {t('music')}
    +
    +
  • +
  • +
    handleCreate('video')}> + +
    {t('video')}
    +
    +
  • +
+
+
) } diff --git a/src/pages/edit.page.tsx b/src/pages/edit.page.tsx index 751e2696..ff3f2c96 100644 --- a/src/pages/edit.page.tsx +++ b/src/pages/edit.page.tsx @@ -6,6 +6,7 @@ import { Shout } from '../graphql/types.gen' import { useRouter } from '../stores/router' import { apiClient } from '../utils/apiClient' import { useLocalize } from '../context/localize' +import { AuthGuard } from '../components/AuthGuard' const Edit = lazy(() => import('../components/Views/Edit')) @@ -26,24 +27,13 @@ export const EditPage = () => { return ( - - -
-
{t("Let's log in")}
-
-
- } - > - - }> - - - + + + }> + + - + ) } diff --git a/src/pages/profile/profileSecurity.page.tsx b/src/pages/profile/profileSecurity.page.tsx index 2c95bbfb..ac821fd8 100644 --- a/src/pages/profile/profileSecurity.page.tsx +++ b/src/pages/profile/profileSecurity.page.tsx @@ -3,131 +3,134 @@ import styles from './Settings.module.scss' import { Icon } from '../../components/_shared/Icon' import { clsx } from 'clsx' import { ProfileSettingsNavigation } from '../../components/Nav/ProfileSettingsNavigation' +import { AuthGuard } from '../../components/AuthGuard' export const ProfileSecurityPage = () => { return ( -
-
-
-
- + +
+
+
+
+ +
-
-
-
-
-

Вход и безопасность

-

Настройки аккаунта, почты, пароля и способов входа.

+
+
+
+

Вход и безопасность

+

Настройки аккаунта, почты, пароля и способов входа.

-
-

Почта

-
- - -
+ +

Почта

+
+ + +
-

Изменить пароль

-
Текущий пароль
-
- - -
+

Изменить пароль

+
Текущий пароль
+
+ + +
-
Новый пароль
-
- - -
+
Новый пароль
+
+ + +
-
Подтвердите новый пароль
-
- - -
+
Подтвердите новый пароль
+
+ + +
-

Социальные сети

-
Google
-
+

Социальные сети

+
Google
+
+

+ +

+
+ +
VK
+
+

+ +

+
+ +
Facebook
+
+

+ +

+
+ +
Apple
+
+

+ +

+
+ +

-

-
- -
VK
-
-

- -

-
- -
Facebook
-
-

- -

-
- -
Apple
-
-

- -

-
- -
-

- -

-
+ +
-
+ ) } diff --git a/src/pages/profile/profileSettings.page.tsx b/src/pages/profile/profileSettings.page.tsx index da392bda..3b4c3f30 100644 --- a/src/pages/profile/profileSettings.page.tsx +++ b/src/pages/profile/profileSettings.page.tsx @@ -18,6 +18,7 @@ import { createStore } from 'solid-js/store' import { clone } from '../../utils/clone' import SimplifiedEditor from '../../components/Editor/SimplifiedEditor' import { GrowingTextarea } from '../../components/_shared/GrowingTextarea' +import { AuthGuard } from '../../components/AuthGuard' export const ProfileSettingsPage = () => { const { t } = useLocalize() @@ -106,157 +107,163 @@ export const ProfileSettingsPage = () => { return ( - -
-
-
-
- + + +
+
+
+
+ +
-
-
-
-
-

{t('Profile settings')}

-

{t('Here you can customize your profile the way you want.')}

-
-

{t('Userpic')}

-
- -
-

{t('Name')}

-

- {t( - 'Your name will appear on your profile page and as your signature in publications, comments and responses.' - )} -

-
- updateFormField('name', event.currentTarget.value)} - value={form.name} - /> - -
- -

{t('Address on Discourse')}

-
-
- -
- updateFormField('slug', event.currentTarget.value)} - value={form.slug} - class="nolabel" - /> - -

{t(`${slugError()}`)}

-
-
+
+
+
+

{t('Profile settings')}

+

{t('Here you can customize your profile the way you want.')}

+ +

{t('Userpic')}

+
+
-
- -

{t('Introduce')}

- updateFormField('bio', value)} - initialValue={form.bio} - allowEnterKey={false} - maxLength={80} - /> - -

{t('About myself')}

- updateFormField('about', value)} - /> - {/*Нет реализации полей на бэке*/} - {/*

{t('How can I help/skills')}

*/} - {/*
*/} - {/* */} - {/*
*/} - {/*

{t('Where')}

*/} - {/*
*/} - {/* */} - {/* */} - {/*
*/} - - {/*

{t('Date of Birth')}

*/} - {/*
*/} - {/* */} - {/*
*/} - -
-
-

{t('Social networks')}

- -
- -
- handleChangeSocial(event.currentTarget.value)} - /> -
- -

{t('It does not look like url')}

-
-
- - {(link) => ( -
- - -
+

{t('Name')}

+

+ {t( + 'Your name will appear on your profile page and as your signature in publications, comments and responses.' )} - -

-
- setIsFloatingPanelVisible(false)} - /> - +

+
+ updateFormField('name', event.currentTarget.value)} + value={form.name} + /> + +
+ +

{t('Address on Discourse')}

+
+
+ +
+ updateFormField('slug', event.currentTarget.value)} + value={form.slug} + class="nolabel" + /> + +

{t(`${slugError()}`)}

+
+
+
+
+ +

{t('Introduce')}

+ updateFormField('bio', value)} + initialValue={form.bio} + allowEnterKey={false} + maxLength={80} + /> + +

{t('About myself')}

+ updateFormField('about', value)} + /> + {/*Нет реализации полей на бэке*/} + {/*

{t('How can I help/skills')}

*/} + {/*
*/} + {/* */} + {/*
*/} + {/*

{t('Where')}

*/} + {/*
*/} + {/* */} + {/* */} + {/*
*/} + + {/*

{t('Date of Birth')}

*/} + {/*
*/} + {/* */} + {/*
*/} + +
+
+

{t('Social networks')}

+ +
+ +
+ handleChangeSocial(event.currentTarget.value)} + /> +
+ +

{t('It does not look like url')}

+
+
+ + {(link) => ( +
+ + +
+ )} +
+
+
+ setIsFloatingPanelVisible(false)} + /> + +
-
- + + ) } diff --git a/src/pages/profile/profileSubscriptions.page.tsx b/src/pages/profile/profileSubscriptions.page.tsx index 17c41f33..28f9f5ba 100644 --- a/src/pages/profile/profileSubscriptions.page.tsx +++ b/src/pages/profile/profileSubscriptions.page.tsx @@ -1,142 +1,13 @@ import { PageLayout } from '../../components/_shared/PageLayout' -import styles from './Settings.module.scss' -import stylesSettings from '../../styles/FeedSettings.module.scss' -import { clsx } from 'clsx' -import { ProfileSettingsNavigation } from '../../components/Nav/ProfileSettingsNavigation' -import { SearchField } from '../../components/_shared/SearchField' -import { createEffect, createSignal, For, onMount, Show } from 'solid-js' -import { Author, Topic } from '../../graphql/types.gen' -import { apiClient } from '../../utils/apiClient' -import { useSession } from '../../context/session' -import { isAuthor } from '../../utils/isAuthor' -import { useLocalize } from '../../context/localize' -import { SubscriptionFilter } from '../types' -import { Loading } from '../../components/_shared/Loading' -import { TopicCard } from '../../components/Topic/Card' -import { AuthorCard } from '../../components/Author/AuthorCard' -import { dummyFilter } from '../../utils/dummyFilter' +import { AuthGuard } from '../../components/AuthGuard' +import { ProfileSubscriptions } from '../../components/Views/ProfileSubscriptions' export const ProfileSubscriptionsPage = () => { - const { t, lang } = useLocalize() - const { user, isAuthenticated } = useSession() - const [following, setFollowing] = createSignal>([]) - const [filtered, setFiltered] = createSignal>([]) - const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') - const [searchQuery, setSearchQuery] = createSignal('') - - const fetchSubscriptions = async () => { - try { - const [getAuthors, getTopics] = await Promise.all([ - apiClient.getAuthorFollowingUsers({ slug: user().slug }), - apiClient.getAuthorFollowingTopics({ slug: user().slug }) - ]) - setFollowing([...getAuthors, ...getTopics]) - setFiltered([...getAuthors, ...getTopics]) - } catch (error) { - console.error('[fetchSubscriptions] :', error) - throw error - } - } - - onMount(async () => { - if (isAuthenticated()) { - await fetchSubscriptions() - } - }) - - createEffect(() => { - console.log('!!! subscriptionFilter():', subscriptionFilter()) - if (following()) { - if (subscriptionFilter() === 'users') { - setFiltered(following().filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setFiltered(following().filter((s) => 'title' in s)) - } else { - setFiltered(following()) - } - } - if (searchQuery()) { - setFiltered(dummyFilter(following(), searchQuery(), lang())) - } - }) - return ( -
-
-
-
- -
-
- -
-
-
-

{t('My subscriptions')}

-

{t('Here you can manage all your Discourse subscriptions')}

- }> -
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
- -
- setSearchQuery(value)} - class={styles.searchField} - variant="bordered" - /> -
- -
- - {(followingItem) => ( -
- {isAuthor(followingItem) ? ( - - ) : ( - - )} -
- )} -
-
-
-
-
-
-
-
+ + +
) } diff --git a/src/stores/ui.ts b/src/stores/ui.ts index e385ec34..55187e99 100644 --- a/src/stores/ui.ts +++ b/src/stores/ui.ts @@ -48,7 +48,7 @@ export const MODALS: Record = { following: 'following' } -const [modal, setModal] = createSignal(null) +const [modal, setModal] = createSignal() const [warnings, setWarnings] = createSignal([])