Update profile post
This commit is contained in:
parent
7b0bac4eca
commit
22ede100e5
|
@ -3,34 +3,25 @@ import { t } from '../../../utils/intl'
|
||||||
import type { PageProps } from '../../types'
|
import type { PageProps } from '../../types'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Icon } from '../../_shared/Icon'
|
||||||
import ProfileSettingsNavigation from '../../Discours/ProfileSettingsNavigation'
|
import ProfileSettingsNavigation from '../../Discours/ProfileSettingsNavigation'
|
||||||
import { useSession } from '../../../context/session'
|
import { For, createSignal, Show } from 'solid-js'
|
||||||
import { createMemo, For, createSignal, Show, createEffect } from 'solid-js'
|
|
||||||
import { loadAuthor, useAuthorsStore } from '../../../stores/zine/authors'
|
|
||||||
import type { Author } from '../../../graphql/types.gen'
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import styles from './Settings.module.scss'
|
import styles from './Settings.module.scss'
|
||||||
|
import { useProfileForm } from '../../../context/profile'
|
||||||
|
|
||||||
export const ProfileSettingsPage = (props: PageProps) => {
|
export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
const [author, setAuthor] = createSignal<Author>(null)
|
const [addLinkForm, setAddLinkForm] = createSignal<boolean>(false)
|
||||||
const { session } = useSession()
|
const { form, updateFormField, submit } = useProfileForm()
|
||||||
const currentSlug = createMemo(() => session()?.user?.slug)
|
const handleChangeSocial = (value) => {
|
||||||
const { authorEntities } = useAuthorsStore({ authors: [] })
|
updateFormField('links', value)
|
||||||
const currentAuthor = createMemo(() => authorEntities()[currentSlug()])
|
setAddLinkForm(false)
|
||||||
|
}
|
||||||
createEffect(async () => {
|
const handleSubmit = (event: Event): void => {
|
||||||
if (!currentSlug()) return
|
event.preventDefault()
|
||||||
try {
|
submit(form)
|
||||||
await loadAuthor({ slug: currentSlug() })
|
|
||||||
setAuthor(currentAuthor())
|
|
||||||
console.log('!!! currentAuthor:', currentAuthor())
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrap>
|
<PageWrap>
|
||||||
<Show when={author()}>
|
<Show when={form}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="shift-content">
|
<div class="shift-content">
|
||||||
<div class="left-col">
|
<div class="left-col">
|
||||||
|
@ -42,11 +33,11 @@ export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
<div class="col-md-10 col-lg-9 col-xl-8">
|
<div class="col-md-10 col-lg-9 col-xl-8">
|
||||||
<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}>
|
||||||
<h4>{t('Userpic')}</h4>
|
<h4>{t('Userpic')}</h4>
|
||||||
<div class="pretty-form__item">
|
<div class="pretty-form__item">
|
||||||
<div class={styles.avatarContainer}>
|
<div class={styles.avatarContainer}>
|
||||||
<img class={styles.avatar} src={author().userpic} />
|
<img class={styles.avatar} src={form.userpic} alt={form.name} />
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
name="avatar"
|
name="avatar"
|
||||||
|
@ -55,7 +46,6 @@ export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>{t('Name')}</h4>
|
<h4>{t('Name')}</h4>
|
||||||
<p class="description">
|
<p class="description">
|
||||||
{t(
|
{t(
|
||||||
|
@ -67,8 +57,9 @@ export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
type="text"
|
type="text"
|
||||||
name="username"
|
name="username"
|
||||||
id="username"
|
id="username"
|
||||||
placeholder="Имя"
|
placeholder={t('Name')}
|
||||||
value={author().name}
|
onChange={(event) => updateFormField('name', event.currentTarget.value)}
|
||||||
|
value={form.name}
|
||||||
/>
|
/>
|
||||||
<label for="username">Имя</label>
|
<label for="username">Имя</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,7 +73,8 @@ export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
type="text"
|
type="text"
|
||||||
name="user-address"
|
name="user-address"
|
||||||
id="user-address"
|
id="user-address"
|
||||||
value={currentSlug()}
|
onChange={(event) => updateFormField('slug', event.currentTarget.value)}
|
||||||
|
value={form.slug}
|
||||||
class="nolabel"
|
class="nolabel"
|
||||||
/>
|
/>
|
||||||
<p class="form-message form-message--error">
|
<p class="form-message form-message--error">
|
||||||
|
@ -92,52 +84,70 @@ export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>{t('Introduce')}</h4>
|
{/*Нет реализации полей на бэке*/}
|
||||||
<div class="pretty-form__item">
|
{/*<h4>{t('Introduce')}</h4>*/}
|
||||||
<textarea name="presentation" id="presentation" placeholder="Представление" />
|
{/*<div class="pretty-form__item">*/}
|
||||||
<label for="presentation">{t('Introduce')}</label>
|
{/* <textarea name="presentation" id="presentation" placeholder={t('Introduce')} />*/}
|
||||||
</div>
|
{/* <label for="presentation">{t('Introduce')}</label>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
|
||||||
<h4>{t('About myself')}</h4>
|
<h4>{t('About myself')}</h4>
|
||||||
<div class="pretty-form__item">
|
<div class="pretty-form__item">
|
||||||
<textarea name="about" id="about" placeholder="О себе">
|
<textarea
|
||||||
{author().bio}
|
name="about"
|
||||||
</textarea>
|
id="about"
|
||||||
|
placeholder={t('About myself')}
|
||||||
|
value={form.bio}
|
||||||
|
onChange={(event) => updateFormField('bio', event.currentTarget.value)}
|
||||||
|
/>
|
||||||
<label for="about">{t('About myself')}</label>
|
<label for="about">{t('About myself')}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>{t('How can I help/skills')}</h4>
|
{/*Нет реализации полей на бэке*/}
|
||||||
<div class="pretty-form__item">
|
{/*<h4>{t('How can I help/skills')}</h4>*/}
|
||||||
<input type="text" name="skills" id="skills" />
|
{/*<div class="pretty-form__item">*/}
|
||||||
</div>
|
{/* <input type="text" name="skills" id="skills" />*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
{/*<h4>{t('Where')}</h4>*/}
|
||||||
|
{/*<div class="pretty-form__item">*/}
|
||||||
|
{/* <input type="text" name="location" id="location" placeholder="Откуда" />*/}
|
||||||
|
{/* <label for="location">{t('Where')}</label>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
|
||||||
<h4>{t('Where')}</h4>
|
{/*<h4>{t('Date of Birth')}</h4>*/}
|
||||||
<div class="pretty-form__item">
|
{/*<div class="pretty-form__item">*/}
|
||||||
<input type="text" name="location" id="location" placeholder="Откуда" />
|
{/* <input*/}
|
||||||
<label for="location">{t('Where')}</label>
|
{/* type="date"*/}
|
||||||
</div>
|
{/* name="birthdate"*/}
|
||||||
|
{/* id="birthdate"*/}
|
||||||
<h4>{t('Date of Birth')}</h4>
|
{/* placeholder="Дата рождения"*/}
|
||||||
<div class="pretty-form__item">
|
{/* class="nolabel"*/}
|
||||||
<input
|
{/* />*/}
|
||||||
type="date"
|
{/*</div>*/}
|
||||||
name="birthdate"
|
|
||||||
id="birthdate"
|
|
||||||
placeholder="Дата рождения"
|
|
||||||
class="nolabel"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class={clsx(styles.multipleControls, 'pretty-form__item')}>
|
<div class={clsx(styles.multipleControls, 'pretty-form__item')}>
|
||||||
<div class={styles.multipleControlsHeader}>
|
<div class={styles.multipleControlsHeader}>
|
||||||
<h4>{t('Social networks')}</h4>
|
<h4>{t('Social networks')}</h4>
|
||||||
<button class="button">+</button>
|
<button type="button" class="button" onClick={() => setAddLinkForm(!addLinkForm())}>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<For each={author().links}>
|
<Show when={addLinkForm()}>
|
||||||
|
<div class={styles.multipleControlsItem}>
|
||||||
|
<input
|
||||||
|
autofocus={true}
|
||||||
|
type="text"
|
||||||
|
name="link"
|
||||||
|
class="nolabel"
|
||||||
|
onChange={(event) => handleChangeSocial(event.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<For each={form.links}>
|
||||||
{(link) => (
|
{(link) => (
|
||||||
<div class={styles.multipleControlsItem}>
|
<div class={styles.multipleControlsItem}>
|
||||||
<input type="text" value={link} name="social1" class="nolabel" />
|
<input type="text" value={link} readonly={true} name="link" class="nolabel" />
|
||||||
<button>
|
<button type="button" onClick={() => updateFormField('links', link, true)}>
|
||||||
<Icon name="remove" class={styles.icon} />
|
<Icon name="remove" class={styles.icon} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -147,12 +157,15 @@ export const ProfileSettingsPage = (props: PageProps) => {
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<p>
|
<p>
|
||||||
<button class="button button--submit">{t('Save settings')}</button>
|
<button type="submit" class="button button--submit">
|
||||||
|
{t('Save settings')}
|
||||||
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<pre>{JSON.stringify(form, null, 2)}</pre>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</PageWrap>
|
</PageWrap>
|
||||||
|
|
61
src/context/profile.tsx
Normal file
61
src/context/profile.tsx
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import { createEffect, createMemo } from 'solid-js'
|
||||||
|
import { createStore } from 'solid-js/store'
|
||||||
|
import { useSession } from './session'
|
||||||
|
import { loadAuthor, useAuthorsStore } from '../stores/zine/authors'
|
||||||
|
import { apiClient } from '../utils/apiClient'
|
||||||
|
import type { ProfileInput } from '../graphql/types.gen'
|
||||||
|
|
||||||
|
const submit = async (profile: ProfileInput) => {
|
||||||
|
try {
|
||||||
|
await apiClient.updateProfile(profile)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const useProfileForm = () => {
|
||||||
|
const { session } = useSession()
|
||||||
|
const currentSlug = createMemo(() => session()?.user?.slug)
|
||||||
|
const { authorEntities } = useAuthorsStore({ authors: [] })
|
||||||
|
const currentAuthor = createMemo(() => authorEntities()[currentSlug()])
|
||||||
|
|
||||||
|
const [form, setForm] = createStore<ProfileInput>({
|
||||||
|
name: '',
|
||||||
|
bio: '',
|
||||||
|
userpic: '',
|
||||||
|
links: []
|
||||||
|
})
|
||||||
|
|
||||||
|
createEffect(async () => {
|
||||||
|
if (!currentSlug()) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await loadAuthor({ slug: currentSlug() })
|
||||||
|
setForm({
|
||||||
|
name: currentAuthor()?.name,
|
||||||
|
bio: currentAuthor()?.bio,
|
||||||
|
userpic: currentAuthor()?.userpic,
|
||||||
|
links: currentAuthor()?.links
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateFormField = (fieldName: string, value: string, remove?: boolean) => {
|
||||||
|
if (fieldName === 'links') {
|
||||||
|
if (remove) {
|
||||||
|
setForm((prev) => ({ ...prev, links: [...prev?.links.filter((item) => item !== value)] }))
|
||||||
|
} else {
|
||||||
|
setForm((prev) => ({ ...prev, links: [...prev?.links, value] }))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setForm({
|
||||||
|
[fieldName]: value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { form, submit, updateFormField }
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useProfileForm }
|
|
@ -2,17 +2,15 @@ import { gql } from '@urql/core'
|
||||||
// WARNING: need Auth header
|
// WARNING: need Auth header
|
||||||
|
|
||||||
export default gql`
|
export default gql`
|
||||||
mutation ProfileUpdateMutation($user: User!) {
|
mutation ProfileUpdateMutation($profile: ProfileInput!) {
|
||||||
profileUpdate(user: $user) {
|
updateProfile(profile: $profile) {
|
||||||
error
|
error
|
||||||
token
|
author {
|
||||||
user {
|
|
||||||
_id: slug
|
|
||||||
name
|
name
|
||||||
slug
|
slug
|
||||||
userpic
|
userpic
|
||||||
bio
|
bio
|
||||||
# links
|
links
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,9 @@ import type {
|
||||||
QueryLoadMessagesByArgs,
|
QueryLoadMessagesByArgs,
|
||||||
MutationCreateChatArgs,
|
MutationCreateChatArgs,
|
||||||
MutationCreateMessageArgs,
|
MutationCreateMessageArgs,
|
||||||
QueryLoadRecipientsArgs
|
QueryLoadRecipientsArgs,
|
||||||
|
User,
|
||||||
|
ProfileInput
|
||||||
} from '../graphql/types.gen'
|
} from '../graphql/types.gen'
|
||||||
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
||||||
import { getToken, privateGraphQLClient } from '../graphql/privateGraphQLClient'
|
import { getToken, privateGraphQLClient } from '../graphql/privateGraphQLClient'
|
||||||
|
@ -42,6 +44,7 @@ import shoutsLoadBy from '../graphql/query/articles-load-by'
|
||||||
import shoutLoad from '../graphql/query/article-load'
|
import shoutLoad from '../graphql/query/article-load'
|
||||||
import loadRecipients from '../graphql/query/chat-recipients'
|
import loadRecipients from '../graphql/query/chat-recipients'
|
||||||
import createMessage from '../graphql/mutation/create-chat-message'
|
import createMessage from '../graphql/mutation/create-chat-message'
|
||||||
|
import updateProfile from '../graphql/mutation/update-profile'
|
||||||
|
|
||||||
type ApiErrorCode =
|
type ApiErrorCode =
|
||||||
| 'unknown'
|
| 'unknown'
|
||||||
|
@ -213,6 +216,10 @@ export const apiClient = {
|
||||||
console.debug('getAuthor', response)
|
console.debug('getAuthor', response)
|
||||||
return response.data.getAuthor
|
return response.data.getAuthor
|
||||||
},
|
},
|
||||||
|
updateProfile: async (options: ProfileInput) => {
|
||||||
|
const response = await privateGraphQLClient.mutation(updateProfile, options).toPromise()
|
||||||
|
console.debug('updateProfile', response)
|
||||||
|
},
|
||||||
getTopic: async ({ slug }: { slug: string }): Promise<Topic> => {
|
getTopic: async ({ slug }: { slug: string }): Promise<Topic> => {
|
||||||
const response = await publicGraphQLClient.query(topicBySlug, { slug }).toPromise()
|
const response = await publicGraphQLClient.query(topicBySlug, { slug }).toPromise()
|
||||||
return response.data.getTopic
|
return response.data.getTopic
|
||||||
|
|
Loading…
Reference in New Issue
Block a user