Profile settings update view (#214)

Profile settings update view
This commit is contained in:
Ilya Y 2023-09-09 15:04:46 +03:00 committed by GitHub
parent 5d116ede22
commit 9c7f6249a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 77 deletions

View File

@ -19,7 +19,7 @@ import { TopicCard } from '../../Topic/Card'
import { getNumeralsDeclension } from '../../../utils/getNumeralsDeclension' import { getNumeralsDeclension } from '../../../utils/getNumeralsDeclension'
type SubscriptionFilter = 'all' | 'users' | 'topics' type SubscriptionFilter = 'all' | 'users' | 'topics'
type AuthorCardProps = { type Props = {
caption?: string caption?: string
hideWriteButton?: boolean hideWriteButton?: boolean
hideDescription?: boolean hideDescription?: boolean
@ -46,7 +46,7 @@ function isAuthor(value: Author | Topic): value is Author {
return 'name' in value return 'name' in value
} }
export const AuthorCard = (props: AuthorCardProps) => { export const AuthorCard = (props: Props) => {
const { t, lang } = useLocalize() const { t, lang } = useLocalize()
const { const {
@ -58,6 +58,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
const [isSubscribing, setIsSubscribing] = createSignal(false) const [isSubscribing, setIsSubscribing] = createSignal(false)
const [subscriptions, setSubscriptions] = createSignal<Array<Author | Topic>>(props.subscriptions) const [subscriptions, setSubscriptions] = createSignal<Array<Author | Topic>>(props.subscriptions)
const [subscriptionFilter, setSubscriptionFilter] = createSignal<SubscriptionFilter>('all') const [subscriptionFilter, setSubscriptionFilter] = createSignal<SubscriptionFilter>('all')
const [userpicUrl, setUserpicUrl] = createSignal<string>()
const subscribed = createMemo<boolean>(() => { const subscribed = createMemo<boolean>(() => {
return session()?.news?.authors?.some((u) => u === props.author.slug) || false return session()?.news?.authors?.some((u) => u === props.author.slug) || false
@ -115,6 +116,10 @@ export const AuthorCard = (props: AuthorCardProps) => {
} }
}) })
if (props.isAuthorPage && props.author.userpic.includes('assets.discours.io')) {
setUserpicUrl(props.author.userpic.replace('100x', '500x500'))
}
return ( return (
<> <>
<div <div
@ -145,7 +150,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
<div class="col-md-5"> <div class="col-md-5">
<Userpic <Userpic
name={props.author.name} name={props.author.name}
userpic={props.author.userpic} userpic={userpicUrl()}
hasLink={props.hasLink} hasLink={props.hasLink}
isBig={props.isAuthorPage} isBig={props.isAuthorPage}
isAuthorsList={props.isAuthorsList} isAuthorsList={props.isAuthorsList}

View File

@ -220,8 +220,8 @@ const SimplifiedEditor = (props: Props) => {
}) })
onCleanup(() => { onCleanup(() => {
editor().destroy()
window.removeEventListener('keydown', handleKeyDown) window.removeEventListener('keydown', handleKeyDown)
editor().destroy()
}) })
if (props.onChange) { if (props.onChange) {

View File

@ -18,7 +18,7 @@ import { useLocalize } from '../../../context/localize'
import { AuthorRatingControl } from '../../Author/AuthorRatingControl' import { AuthorRatingControl } from '../../Author/AuthorRatingControl'
import { hideModal } from '../../../stores/ui' import { hideModal } from '../../../stores/ui'
type AuthorProps = { type Props = {
shouts: Shout[] shouts: Shout[]
author: Author author: Author
authorSlug: string authorSlug: string
@ -31,7 +31,7 @@ export type AuthorPageSearchParams = {
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: AuthorProps) => { export const AuthorView = (props: Props) => {
const { t } = useLocalize() const { t } = useLocalize()
const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) const { sortedArticles } = useArticlesStore({ shouts: props.shouts })
const { searchParams, changeSearchParam } = useRouter<AuthorPageSearchParams>() const { searchParams, changeSearchParam } = useRouter<AuthorPageSearchParams>()
@ -127,6 +127,7 @@ export const AuthorView = (props: AuthorProps) => {
} }
} }
}) })
return ( return (
<div class={styles.authorPage}> <div class={styles.authorPage}>
<div class="wide-container"> <div class="wide-container">

View File

@ -1,6 +1,6 @@
import { clsx } from 'clsx' import { clsx } from 'clsx'
import styles from './GrowingTextarea.module.scss' import styles from './GrowingTextarea.module.scss'
import { createSignal, Show } from 'solid-js' import { createEffect, createSignal, onMount, Show } from 'solid-js'
type Props = { type Props = {
class?: string class?: string
@ -15,8 +15,16 @@ type Props = {
} }
export const GrowingTextarea = (props: Props) => { export const GrowingTextarea = (props: Props) => {
const [value, setValue] = createSignal<string>(props.initialValue ?? '') const [value, setValue] = createSignal<string>()
const [isFocused, setIsFocused] = createSignal(false) const [isFocused, setIsFocused] = createSignal(false)
createEffect(() => {
if (props.maxLength && props.initialValue?.length > props.maxLength) {
setValue(props.initialValue.slice(0, props.maxLength))
} else {
setValue(props.initialValue ?? '')
}
})
const handleChangeValue = (event) => { const handleChangeValue = (event) => {
setValue(event.target.value) setValue(event.target.value)
} }
@ -32,43 +40,45 @@ export const GrowingTextarea = (props: Props) => {
} }
return ( return (
<div <Show when={value()}>
class={clsx(styles.GrowingTextarea, { <div
[styles.bordered]: props.variant === 'bordered', class={clsx(styles.GrowingTextarea, {
[styles.hasFieldName]: props.fieldName && value().length > 0 [styles.bordered]: props.variant === 'bordered',
})} [styles.hasFieldName]: props.fieldName && value().length > 0
> })}
<Show when={props.fieldName && value().length > 0}> >
<div class={styles.fieldName}>{props.fieldName}</div> <Show when={props.fieldName && value().length > 0}>
</Show> <div class={styles.fieldName}>{props.fieldName}</div>
<div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}> </Show>
<textarea <div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}>
ref={props.textAreaRef} <textarea
rows={1} ref={props.textAreaRef}
maxlength={props.maxLength} rows={1}
autocomplete="off" maxlength={props.maxLength}
class={clsx(styles.textInput, props.class)} autocomplete="off"
value={props.initialValue} class={clsx(styles.textInput, props.class)}
onKeyDown={props.allowEnterKey ? handleKeyDown : null} value={props.maxLength ? props.initialValue.slice(0, props.maxLength) : props.initialValue}
onInput={(event) => handleChangeValue(event)} onKeyDown={props.allowEnterKey ? handleKeyDown : null}
onChange={(event) => props.value(event.target.value)} onInput={(event) => handleChangeValue(event)}
placeholder={props.placeholder} onChange={(event) => props.value(event.target.value)}
onFocus={() => setIsFocused(true)} placeholder={props.placeholder}
onBlur={() => setIsFocused(false)} onFocus={() => setIsFocused(true)}
/> onBlur={() => setIsFocused(false)}
</div> />
<Show when={(props.maxLength && value() && isFocused()) || props.variant === 'bordered'}>
<div
class={clsx(styles.maxLength, {
[styles.visible]: isFocused(),
[styles.limited]: value().length === props.maxLength
})}
>
<Show when={props.variant === 'bordered'} fallback={`${value().length} / ${props.maxLength}`}>
{`${props.maxLength - value().length}`}
</Show>
</div> </div>
</Show> <Show when={(props.maxLength && value() && isFocused()) || props.variant === 'bordered'}>
</div> <div
class={clsx(styles.maxLength, {
[styles.visible]: isFocused(),
[styles.limited]: value().length === props.maxLength
})}
>
<Show when={props.variant === 'bordered'} fallback={`${value().length} / ${props.maxLength}`}>
{`${props.maxLength - value().length}`}
</Show>
</div>
</Show>
</div>
</Show>
) )
} }

View File

@ -40,7 +40,7 @@ const useProfileForm = () => {
slug: currentAuthor()?.slug, slug: currentAuthor()?.slug,
bio: currentAuthor()?.bio, bio: currentAuthor()?.bio,
about: currentAuthor()?.about, about: currentAuthor()?.about,
userpic: currentAuthor()?.userpic, userpic: currentAuthor()?.userpic.replace('100x', '500x500'),
links: currentAuthor()?.links links: currentAuthor()?.links
}) })
} catch (error) { } catch (error) {

View File

@ -1,7 +1,7 @@
import { PageLayout } from '../../components/_shared/PageLayout' import { PageLayout } from '../../components/_shared/PageLayout'
import { Icon } from '../../components/_shared/Icon' import { Icon } from '../../components/_shared/Icon'
import ProfileSettingsNavigation from '../../components/Discours/ProfileSettingsNavigation' import ProfileSettingsNavigation from '../../components/Discours/ProfileSettingsNavigation'
import { For, createSignal, Show, onMount, onCleanup } from 'solid-js' import { For, createSignal, Show, onMount, onCleanup, createEffect, on } from 'solid-js'
import deepEqual from 'fast-deep-equal' import deepEqual from 'fast-deep-equal'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import styles from './Settings.module.scss' import styles from './Settings.module.scss'
@ -16,6 +16,9 @@ import { handleFileUpload } from '../../utils/handleFileUpload'
import { Userpic } from '../../components/Author/Userpic' import { Userpic } from '../../components/Author/Userpic'
import { createStore } from 'solid-js/store' import { createStore } from 'solid-js/store'
import { clone } from '../../utils/clone' import { clone } from '../../utils/clone'
import SimplifiedEditor from '../../components/Editor/SimplifiedEditor'
import { GrowingTextarea } from '../../components/_shared/GrowingTextarea'
import { resetSortedArticles } from '../../stores/zine/articles'
export const ProfileSettingsPage = () => { export const ProfileSettingsPage = () => {
const { t } = useLocalize() const { t } = useLocalize()
@ -96,6 +99,12 @@ export const ProfileSettingsPage = () => {
setPrevForm(clone(form)) setPrevForm(clone(form))
} }
createEffect(() => {
if (!deepEqual(form, prevForm)) {
setIsFloatingPanelVisible(true)
}
})
return ( return (
<PageLayout> <PageLayout>
<Show when={form}> <Show when={form}>
@ -111,15 +120,7 @@ export const ProfileSettingsPage = () => {
<div class="col-md-20 col-lg-18 col-xl-16"> <div class="col-md-20 col-lg-18 col-xl-16">
<h1>{t('Profile settings')}</h1> <h1>{t('Profile settings')}</h1>
<p class="description">{t('Here you can customize your profile the way you want.')}</p> <p class="description">{t('Here you can customize your profile the way you want.')}</p>
<form <form onSubmit={handleSubmit} enctype="multipart/form-data">
onSubmit={handleSubmit}
onChange={() => {
if (!deepEqual(form, prevForm)) {
setIsFloatingPanelVisible(true)
}
}}
enctype="multipart/form-data"
>
<h4>{t('Userpic')}</h4> <h4>{t('Userpic')}</h4>
<div class="pretty-form__item"> <div class="pretty-form__item">
<Userpic <Userpic
@ -169,29 +170,26 @@ export const ProfileSettingsPage = () => {
</div> </div>
<h4>{t('Introduce')}</h4> <h4>{t('Introduce')}</h4>
<div class="pretty-form__item"> <GrowingTextarea
<textarea variant="bordered"
name="bio" placeholder={t('Introduce')}
id="bio" value={(value) => updateFormField('bio', value)}
placeholder={t('Introduce')} initialValue={form.bio}
value={form.bio} allowEnterKey={false}
onChange={(event) => updateFormField('bio', event.currentTarget.value)} maxLength={80}
/> />
<label for="presentation">{t('Introduce')}</label>
</div>
<h4>{t('About myself')}</h4> <h4>{t('About myself')}</h4>
<div class="pretty-form__item"> <SimplifiedEditor
<textarea variant="bordered"
name="about" onlyBubbleControls={true}
id="about" smallHeight={true}
placeholder={t('About myself')} placeholder={t('About myself')}
value={form.about} label={t('About myself')}
onChange={(event) => updateFormField('about', event.currentTarget.value)} initialContent={form.about}
/> onChange={(value) => updateFormField('about', value)}
<label for="about">{t('About myself')}</label> maxLength={500}
</div> />
{/*Нет реализации полей на бэке*/} {/*Нет реализации полей на бэке*/}
{/*<h4>{t('How can I help/skills')}</h4>*/} {/*<h4>{t('How can I help/skills')}</h4>*/}
{/*<div class="pretty-form__item">*/} {/*<div class="pretty-form__item">*/}