diff --git a/src/app/common/components/modals/validators/socialLinkValidator.tsx b/src/app/common/components/modals/validators/socialLinkValidator.tsx new file mode 100644 index 000000000..98c218bb2 --- /dev/null +++ b/src/app/common/components/modals/validators/socialLinkValidator.tsx @@ -0,0 +1,36 @@ +/* eslint-disable import/extensions */ + +import { doesUrlContainSiteName, isInvalidUrl } from '@/app/common/utils/checkUrl'; +import SocialItem from '@/models/social-link/socialItem'; + +export default function validateSocialLink( + link: string, + socialOptions: SocialItem[], + logoTypes: string[], + sourceLinks: { logoType: T }[], + socialName: string, +): Promise { + if (!link || isInvalidUrl(link)) { + return Promise.reject(new Error( + 'Недійсний формат посилання', + )); + } + + const logotype = socialOptions.find((opt) => opt.value === socialName)?.logo; + if (logotype === undefined // we need this explicit check because it can pass when logotype is 0 + || logotype === null + || (!doesUrlContainSiteName(link, logoTypes[Number(logotype)]))) { + return Promise.reject(new Error( + 'Посилання не співпадає з вибраним текстом', + )); + } + + const doesLinkWithLogoTypeAlreadyExist = sourceLinks.some((obj) => obj.logoType === Number(logotype)); + if (doesLinkWithLogoTypeAlreadyExist) { + return Promise.reject(new Error( + 'Посилання на таку соціальну мережу вже додано', + )); + } + + return Promise.resolve(); +} diff --git a/src/features/AdminPage/PartnersPage/PartnerModal/PartnerModal.component.tsx b/src/features/AdminPage/PartnersPage/PartnerModal/PartnerModal.component.tsx index c78066e8a..32b54f227 100644 --- a/src/features/AdminPage/PartnersPage/PartnerModal/PartnerModal.component.tsx +++ b/src/features/AdminPage/PartnersPage/PartnerModal/PartnerModal.component.tsx @@ -21,7 +21,7 @@ import TextArea from 'antd/es/input/TextArea'; import FileUploader from '@/app/common/components/FileUploader/FileUploader.component'; import base64ToUrl from '@/app/common/utils/base64ToUrl.utility'; -import { doesUrlContainSiteName, isInvalidUrl } from '@/app/common/utils/checkUrl'; +import validateSocialLink from '@/app/common/components/modals/validators/socialLinkValidator'; import ImageStore from '@/app/stores/image-store'; import PartnerLink from '@/features/AdminPage/PartnersPage/PartnerLink.component'; import Audio from '@/models/media/audio.model'; @@ -51,6 +51,7 @@ const PartnerModal: React.FC< { }) => { // eslint-disable-next-line max-len,no-useless-escape const URL_REGEX_VALIDATION_PATTERN = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,256}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/; + const LOGO_TYPES = Object.keys(LogoType).filter((key) => Number.isNaN(Number(key))); const [form] = Form.useForm(); const [urlTitleEnabled, setUrlTitleEnabled] = useState(''); const [urlTitleValue, setUrlTitleValue] = useState(''); @@ -508,29 +509,14 @@ const PartnerModal: React.FC< { }, { validator: (_, value) => { - if (!value || isInvalidUrl(value)) { - return Promise.reject(new Error( - 'Недійсний формат посилання', - )); - } - const socialName = partnerLinksForm.getFieldValue('logotype'); - const logotype = SOCIAL_OPTIONS.find((opt) => opt.value === socialName)?.logo; - if (logotype === undefined // we need this explicit undefined check because it can pass when logotype is 0 - || (!doesUrlContainSiteName(value, LogoType[logotype]))) { - return Promise.reject(new Error( - 'Посилання не співпадає з вибраним текстом', - )); - } - - const doesLinkWithLogoTypeAlreadyExist = partnerSourceLinks.some((obj) => obj.logoType === Number(logotype)); - if (doesLinkWithLogoTypeAlreadyExist) { - return Promise.reject(new Error( - 'Посилання на таку соціальну мережу вже додано', - )); - } - - return Promise.resolve(); + return validateSocialLink( + value, + SOCIAL_OPTIONS, + LOGO_TYPES, + partnerSourceLinks, + socialName, + ); }, }, ]} diff --git a/src/features/AdminPage/PartnersPage/PartnerModal/constants/socialOptions.ts b/src/features/AdminPage/PartnersPage/PartnerModal/constants/socialOptions.ts index 57747745f..a9c2ec774 100644 --- a/src/features/AdminPage/PartnersPage/PartnerModal/constants/socialOptions.ts +++ b/src/features/AdminPage/PartnersPage/PartnerModal/constants/socialOptions.ts @@ -1,12 +1,9 @@ -import { LogoType } from '@/models/team/team.model'; +/* eslint-disable import/extensions */ -interface SocialItem { - label: string - value: string - logo: LogoType -} +import { LogoType } from '@/models/partners/partners.model'; +import SocialItem from '@/models/social-link/socialItem'; -const SOCIAL_OPTIONS: SocialItem[] = [ +const SOCIAL_OPTIONS: SocialItem[] = [ { value: 'x', label: 'X', diff --git a/src/features/AdminPage/TeamPage/TeamModal/TeamModal.component.tsx b/src/features/AdminPage/TeamPage/TeamModal/TeamModal.component.tsx index bbe0711ca..28354984e 100644 --- a/src/features/AdminPage/TeamPage/TeamModal/TeamModal.component.tsx +++ b/src/features/AdminPage/TeamPage/TeamModal/TeamModal.component.tsx @@ -26,18 +26,18 @@ import { Option } from 'antd/es/mentions'; import PositionsApi from '@/app/api/team/positions.api'; import FileUploader from '@/app/common/components/FileUploader/FileUploader.component'; import base64ToUrl from '@/app/common/utils/base64ToUrl.utility'; -import { doesUrlContainSiteName, isInvalidUrl } from '@/app/common/utils/checkUrl'; +import validateSocialLink from '@/app/common/components/modals/validators/socialLinkValidator'; import TeamLink from '@/features/AdminPage/TeamPage/TeamLink.component'; import Audio from '@/models/media/audio.model'; import Image from '@/models/media/image.model'; import POPOVER_CONTENT from '../../JobsPage/JobsModal/constants/popoverContent'; -import { constant } from 'lodash'; const TeamModal: React.FC<{ teamMember?: TeamMember, open: boolean, setIsModalOpen: React.Dispatch>, afterSubmit?: (team: TeamCreateUpdate) => void }> = observer(({ teamMember, open, setIsModalOpen, afterSubmit }) => { + const LOGO_TYPES = Object.keys(LogoType).filter((key) => Number.isNaN(Number(key))); const [form] = Form.useForm(); const { teamStore } = useMobx(); const [positions, setPositions] = useState([]); @@ -371,29 +371,14 @@ const TeamModal: React.FC<{ { required: true, message: 'Введіть посилання' }, { validator: (_, value) => { - if (!value || isInvalidUrl(value)) { - return Promise.reject(new Error( - 'Недійсний формат посилання', - )); - } - const socialName = teamLinksForm.getFieldValue('logotype'); - const logotype = SOCIAL_OPTIONS.find((opt) => opt.value === socialName)?.logo; - if (logotype === undefined // we need this explicit undefined check because it can pass when logotype is 0 - || (logotype !== LogoType.http && !doesUrlContainSiteName(value, LogoType[logotype]))) { - return Promise.reject(new Error( - 'Посилання не співпадає з вибраним текстом', - )); - } - - const doesLinkWithLogoTypeAlreadyExist = teamSourceLinks.some((obj) => obj.logoType === Number(logotype)); - if (doesLinkWithLogoTypeAlreadyExist) { - return Promise.reject(new Error( - 'Посилання на таку соціальну мережу вже додано', - )); - } - - return Promise.resolve(); + return validateSocialLink( + value, + SOCIAL_OPTIONS, + LOGO_TYPES, + teamSourceLinks, + socialName, + ); }, }, ]} diff --git a/src/features/AdminPage/TeamPage/TeamModal/constants/socialOptions.ts b/src/features/AdminPage/TeamPage/TeamModal/constants/socialOptions.ts index 3771862f0..96e9b9b25 100644 --- a/src/features/AdminPage/TeamPage/TeamModal/constants/socialOptions.ts +++ b/src/features/AdminPage/TeamPage/TeamModal/constants/socialOptions.ts @@ -1,11 +1,9 @@ +/* eslint-disable import/extensions */ + +import SocialItem from '@/models/social-link/socialItem'; import { LogoType } from '@/models/team/team.model'; -interface SocialItem { - label: string - value: string - logo: LogoType -} -const SOCIAL_OPTIONS: SocialItem[] = [ +const SOCIAL_OPTIONS: SocialItem[] = [ { value: 'x.com', label: 'X', diff --git a/src/models/social-link/socialItem.ts b/src/models/social-link/socialItem.ts new file mode 100644 index 000000000..c7824a3b8 --- /dev/null +++ b/src/models/social-link/socialItem.ts @@ -0,0 +1,5 @@ +export default interface SocialItem { + label: string + value: string + logo: T +}