diff --git a/src/components/Pages/profile/ProfileSettingsPage.tsx b/src/components/Pages/profile/ProfileSettingsPage.tsx index 64e21ead..79a5f10c 100644 --- a/src/components/Pages/profile/ProfileSettingsPage.tsx +++ b/src/components/Pages/profile/ProfileSettingsPage.tsx @@ -8,13 +8,19 @@ import { clsx } from 'clsx' import styles from './Settings.module.scss' import { useProfileForm } from '../../../context/profile' import { createFileUploader } from '@solid-primitives/upload' +import validateUrl from '../../../utils/validateUrl' export const ProfileSettingsPage = (props: PageProps) => { const [addLinkForm, setAddLinkForm] = createSignal(false) - const { form, updateFormField, submit } = useProfileForm() + const [incorrectUrl, setIncorrectUrl] = createSignal(false) + const { form, updateFormField, submit, error } = useProfileForm() const handleChangeSocial = (value) => { - updateFormField('links', value) - setAddLinkForm(false) + if (validateUrl(value)) { + updateFormField('links', value) + setAddLinkForm(false) + } else { + setIncorrectUrl(true) + } } const handleSubmit = (event: Event): void => { event.preventDefault() @@ -98,9 +104,7 @@ export const ProfileSettingsPage = (props: PageProps) => { value={form.slug} class="nolabel" /> -

- {t('Sorry, this address is already taken, please choose another one.')} -

+

{t(`error()`)}

@@ -164,6 +168,9 @@ export const ProfileSettingsPage = (props: PageProps) => { onChange={(event) => handleChangeSocial(event.currentTarget.value)} /> + +

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

+
{(link) => ( diff --git a/src/context/profile.tsx b/src/context/profile.tsx index 6f54a45d..a90ba650 100644 --- a/src/context/profile.tsx +++ b/src/context/profile.tsx @@ -1,23 +1,29 @@ -import { createEffect, createMemo } from 'solid-js' +import { createEffect, createMemo, createSignal } 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 [error, setError] = createSignal() + + const submit = async (profile: ProfileInput) => { + try { + const response = await apiClient.updateProfile(profile) + if (response.error) { + setError(response.error) + return response.error + } + return response + } catch (error) { + console.error(error) + } + } const [form, setForm] = createStore({ name: '', @@ -29,7 +35,6 @@ const useProfileForm = () => { createEffect(async () => { if (!currentSlug()) return - try { await loadAuthor({ slug: currentSlug() }) setForm({ @@ -60,7 +65,7 @@ const useProfileForm = () => { }) } } - return { form, submit, updateFormField } + return { form, submit, updateFormField, error } } export { useProfileForm } diff --git a/src/locales/ru.json b/src/locales/ru.json index 53fae93b..3368f05e 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -203,5 +203,7 @@ "Where": "Откуда", "Date of Birth": "Дата рождения", "Social networks": "Социальные сети", - "Save settings": "Сохранить настройки" + "Save settings": "Сохранить настройки", + "slug is used by another user": "Имя уже занято другим пользователем", + "It does not look like url": "Это не похоже на ссылку" } diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index 4b1b709c..63a15c64 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -213,12 +213,12 @@ export const apiClient = { }, getAuthor: async ({ slug }: { slug: string }): Promise => { const response = await publicGraphQLClient.query(authorBySlug, { slug }).toPromise() - // console.debug('getAuthor', response) return response.data.getAuthor }, updateProfile: async (input: ProfileInput) => { const response = await privateGraphQLClient.mutation(updateProfile, { profile: input }).toPromise() - console.debug('updateProfile', response) + console.log('!!! response.data.getAuthor:', response.data.updateProfile) + return response.data.updateProfile }, getTopic: async ({ slug }: { slug: string }): Promise => { const response = await publicGraphQLClient.query(topicBySlug, { slug }).toPromise() diff --git a/src/utils/validateUrl.ts b/src/utils/validateUrl.ts new file mode 100644 index 00000000..aaba15f6 --- /dev/null +++ b/src/utils/validateUrl.ts @@ -0,0 +1,7 @@ +const validateUrl = (value: string) => { + return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( + value + ) +} + +export default validateUrl