From 5d5f4ccfdf935b3bbf5734e1fbaad28af4f51af0 Mon Sep 17 00:00:00 2001
From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com>
Date: Thu, 9 Nov 2023 17:29:48 +0300
Subject: [PATCH] Feature/social input (#299)
Social input in profile
---
public/icons/social-facebook.svg | 3 ++
public/icons/social-instagram.svg | 5 ++
public/icons/social-linkedin.svg | 7 +++
public/icons/social-telegram.svg | 5 ++
public/icons/social-vk.svg | 3 ++
.../SocialNetworkInput.module.scss | 50 +++++++++++++++++++
.../SocialNetworkInput/SocialNetworkInput.tsx | 44 ++++++++++++++++
.../_shared/SocialNetworkInput/index.ts | 1 +
.../_shared/SolidSwiper/ArticleCardSwiper.tsx | 2 +-
src/context/profile.tsx | 4 ++
src/pages/profile/Settings.module.scss | 4 ++
src/pages/profile/profileSettings.page.tsx | 47 ++++++++++-------
src/utils/profileSocialLinks.ts | 50 +++++++++++++++++++
13 files changed, 205 insertions(+), 20 deletions(-)
create mode 100644 public/icons/social-facebook.svg
create mode 100644 public/icons/social-instagram.svg
create mode 100644 public/icons/social-linkedin.svg
create mode 100644 public/icons/social-telegram.svg
create mode 100644 public/icons/social-vk.svg
create mode 100644 src/components/_shared/SocialNetworkInput/SocialNetworkInput.module.scss
create mode 100644 src/components/_shared/SocialNetworkInput/SocialNetworkInput.tsx
create mode 100644 src/components/_shared/SocialNetworkInput/index.ts
create mode 100644 src/utils/profileSocialLinks.ts
diff --git a/public/icons/social-facebook.svg b/public/icons/social-facebook.svg
new file mode 100644
index 00000000..10e45710
--- /dev/null
+++ b/public/icons/social-facebook.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/icons/social-instagram.svg b/public/icons/social-instagram.svg
new file mode 100644
index 00000000..05db9472
--- /dev/null
+++ b/public/icons/social-instagram.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/icons/social-linkedin.svg b/public/icons/social-linkedin.svg
new file mode 100644
index 00000000..d0bb452e
--- /dev/null
+++ b/public/icons/social-linkedin.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/icons/social-telegram.svg b/public/icons/social-telegram.svg
new file mode 100644
index 00000000..420cb810
--- /dev/null
+++ b/public/icons/social-telegram.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/icons/social-vk.svg b/public/icons/social-vk.svg
new file mode 100644
index 00000000..37b3ea78
--- /dev/null
+++ b/public/icons/social-vk.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/_shared/SocialNetworkInput/SocialNetworkInput.module.scss b/src/components/_shared/SocialNetworkInput/SocialNetworkInput.module.scss
new file mode 100644
index 00000000..65401cdf
--- /dev/null
+++ b/src/components/_shared/SocialNetworkInput/SocialNetworkInput.module.scss
@@ -0,0 +1,50 @@
+.SocialNetworkInput {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ height: 54px;
+ border: 2px solid var(--black-100);
+ border-radius: 2px;
+
+ .icon {
+ width: 54px;
+ height: 54px;
+ padding: 16px;
+ border-right: 2px solid var(--black-100);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .input {
+ @include font-size(1.7rem);
+
+ margin: 0 16px;
+ width: 100%;
+ border: none;
+ height: 1em;
+ padding: 0;
+ display: block;
+ flex: 1;
+
+ &:focus {
+ outline: none;
+ }
+
+ &::placeholder {
+ color: var(--black-300);
+ }
+ }
+
+ .remove {
+ width: 54px;
+ height: 54px;
+ padding: 16px;
+ &:hover {
+ background: var(--background-color-invert);
+ img {
+ filter: invert(1);
+ }
+ }
+ }
+}
diff --git a/src/components/_shared/SocialNetworkInput/SocialNetworkInput.tsx b/src/components/_shared/SocialNetworkInput/SocialNetworkInput.tsx
new file mode 100644
index 00000000..c3008a2a
--- /dev/null
+++ b/src/components/_shared/SocialNetworkInput/SocialNetworkInput.tsx
@@ -0,0 +1,44 @@
+import { clsx } from 'clsx'
+import styles from './SocialNetworkInput.module.scss'
+import { Icon } from '../Icon'
+import { onMount, Show } from 'solid-js'
+
+type Props = {
+ class?: string
+ network?: string
+ link?: string
+ isExist: boolean
+ handleChange: (value: string) => void
+ handleDelete?: () => void
+ slug?: string
+ autofocus?: boolean
+}
+
+export const SocialNetworkInput = (props: Props) => {
+ const inputRef: { current: HTMLInputElement } = { current: null }
+ onMount(() => {
+ if (props.autofocus) {
+ inputRef.current.focus()
+ }
+ })
+ return (
+
+ )
+}
diff --git a/src/components/_shared/SocialNetworkInput/index.ts b/src/components/_shared/SocialNetworkInput/index.ts
new file mode 100644
index 00000000..bb028529
--- /dev/null
+++ b/src/components/_shared/SocialNetworkInput/index.ts
@@ -0,0 +1 @@
+export { SocialNetworkInput } from './SocialNetworkInput'
diff --git a/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx b/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx
index 4c4fbfab..c0b839a8 100644
--- a/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx
+++ b/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx
@@ -49,7 +49,7 @@ export const ArticleCardSwiper = (props: Props) => {
speed={800}
autoplay={{
disableOnInteraction: false,
- delay: 3000,
+ delay: 6000,
pauseOnMouseEnter: true
}}
>
diff --git a/src/context/profile.tsx b/src/context/profile.tsx
index 0038b518..5c55b500 100644
--- a/src/context/profile.tsx
+++ b/src/context/profile.tsx
@@ -69,6 +69,10 @@ const useProfileForm = () => {
})
}
}
+ createEffect(() => {
+ console.log('!!! FL:', form.links)
+ })
+
return { form, submit, updateFormField, slugError }
}
diff --git a/src/pages/profile/Settings.module.scss b/src/pages/profile/Settings.module.scss
index 54d620e3..1bdb7520 100644
--- a/src/pages/profile/Settings.module.scss
+++ b/src/pages/profile/Settings.module.scss
@@ -215,3 +215,7 @@ h5 {
}
}
}
+
+.socialInput {
+ margin-top: 1rem;
+}
diff --git a/src/pages/profile/profileSettings.page.tsx b/src/pages/profile/profileSettings.page.tsx
index c5251456..dccc7cc6 100644
--- a/src/pages/profile/profileSettings.page.tsx
+++ b/src/pages/profile/profileSettings.page.tsx
@@ -1,5 +1,4 @@
import { PageLayout } from '../../components/_shared/PageLayout'
-import { Icon } from '../../components/_shared/Icon'
import { ProfileSettingsNavigation } from '../../components/Nav/ProfileSettingsNavigation'
import { For, createSignal, Show, onMount, onCleanup, createEffect } from 'solid-js'
import deepEqual from 'fast-deep-equal'
@@ -19,11 +18,14 @@ import SimplifiedEditor from '../../components/Editor/SimplifiedEditor'
import { GrowingTextarea } from '../../components/_shared/GrowingTextarea'
import { AuthGuard } from '../../components/AuthGuard'
import { handleImageUpload } from '../../utils/handleImageUpload'
+import { SocialNetworkInput } from '../../components/_shared/SocialNetworkInput'
+import { profileSocialLinks } from '../../utils/profileSocialLinks'
export const ProfileSettingsPage = () => {
const { t } = useLocalize()
const [addLinkForm, setAddLinkForm] = createSignal(false)
const [incorrectUrl, setIncorrectUrl] = createSignal(false)
+
const [isUserpicUpdating, setIsUserpicUpdating] = createSignal(false)
const [uploadError, setUploadError] = createSignal(false)
const [isFloatingPanelVisible, setIsFloatingPanelVisible] = createSignal(false)
@@ -38,7 +40,7 @@ export const ProfileSettingsPage = () => {
const { form, updateFormField, submit, slugError } = useProfileForm()
const [prevForm, setPrevForm] = createStore(clone(form))
-
+ const [social, setSocial] = createSignal(form.links)
const handleChangeSocial = (value: string) => {
if (validateUrl(value)) {
updateFormField('links', value)
@@ -108,6 +110,14 @@ export const ProfileSettingsPage = () => {
}
})
+ const handleDeleteSocialLink = (link) => {
+ updateFormField('links', link, true)
+ }
+
+ createEffect(() => {
+ setSocial(form.links)
+ })
+
return (
@@ -230,27 +240,26 @@ export const ProfileSettingsPage = () => {
-
- handleChangeSocial(event.currentTarget.value)}
- />
-
+ handleChangeSocial(value)}
+ />
{t('It does not look like url')}
-
- {(link) => (
-
-
-
-
+
+ {(network) => (
+ handleChangeSocial(value)}
+ isExist={!network.isPlaceholder}
+ slug={form.slug}
+ handleDelete={() => handleDeleteSocialLink(network.link)}
+ />
)}
diff --git a/src/utils/profileSocialLinks.ts b/src/utils/profileSocialLinks.ts
new file mode 100644
index 00000000..637c1743
--- /dev/null
+++ b/src/utils/profileSocialLinks.ts
@@ -0,0 +1,50 @@
+type Link = {
+ link: string
+ isPlaceholder: boolean
+ name?: string
+}
+
+const links: Link[] = [
+ { link: 'https://facebook.com/', name: 'facebook', isPlaceholder: true },
+ { link: 'https://linkedin.com/', name: 'linkedin', isPlaceholder: true },
+ { link: 'https://vk.com/', name: 'vk', isPlaceholder: true },
+ { link: 'https://instagram.com/', name: 'instagram', isPlaceholder: true },
+ { link: 'https://t.me/', name: 'telegram', isPlaceholder: true }
+]
+
+const checkLink = (link: string, keyword: string): boolean => link.includes(keyword)
+
+export const profileSocialLinks = (socialLinks: string[]): Link[] => {
+ const processedLinks: Link[] = []
+ let unmatchedLinks: string[] = [...socialLinks]
+
+ links.forEach((linkObj) => {
+ let linkMatched = false
+
+ socialLinks.forEach((serverLink) => {
+ if (checkLink(serverLink, new URL(linkObj.link).hostname.replace('www.', ''))) {
+ processedLinks.push({ ...linkObj, link: serverLink, isPlaceholder: false })
+ linkMatched = true
+ unmatchedLinks = unmatchedLinks.filter((unmatchedLink) => unmatchedLink !== serverLink)
+ }
+ })
+
+ if (!linkMatched) {
+ processedLinks.push({ ...linkObj, isPlaceholder: true })
+ }
+ })
+
+ unmatchedLinks.forEach((unmatchedLink) => {
+ processedLinks.push({ link: unmatchedLink, isPlaceholder: false })
+ })
+
+ return processedLinks.sort((a, b) => {
+ if (a.isPlaceholder && !b.isPlaceholder) {
+ return 1
+ } else if (!a.isPlaceholder && b.isPlaceholder) {
+ return -1
+ } else {
+ return 0
+ }
+ })
+}