diff --git a/src/components/EditableText.tsx b/src/components/EditableText.tsx index 064d498..74149e1 100644 --- a/src/components/EditableText.tsx +++ b/src/components/EditableText.tsx @@ -120,12 +120,16 @@ export const EditableText = (props: EditableTextProps) => { props.wrapperClassName ?? '', !props.readOnly && 'editable-text__text-wrapper__editable', ]} - ON_click={() => { + ON_click={(ev: PointerEvent) => { + ev.stopPropagation(); if (!props.readOnly) { setOldText(props.text); setIsInput(true); } }} + ON_mousedown={(ev: PointerEvent) => { + ev.stopPropagation(); + }} >
{ const DND_THRESHOLD = 10; +let timer: number; + export const KanbanCard = (props: KanbanCardProps) => { const activeBoard = useActiveBoardStore() as ActiveBoard; const card = props.card; @@ -76,14 +78,18 @@ export const KanbanCard = (props: KanbanCardProps) => { [x: number, y: number] | undefined >(undefined); const [dragOffset, setDragOffset] = useState<[x: number, y: number]>([0, 0]); - let timer: number; const editCallback = () => { clearTimeout(timer); setIsInput(true); }; + const cancelDnd = () => { + setDragStart(undefined); + }; if (card.type === 'stub') { - return
; + return ( +
+ ); } else { useEffectRefs((refs) => { // Таймаут нужен, чтобы обложка карточки, если она есть, успела загрузиться @@ -97,10 +103,15 @@ export const KanbanCard = (props: KanbanCardProps) => { ref="card" class="kanban-card" ON_mousedown={(ev: PointerEvent) => { - setDragStart([ev.x, ev.y]); - setDragOffset([ev.offsetX, ev.offsetY]); + if (!isInput) { + setDragStart([ev.x, ev.y]); + setDragOffset([ev.offsetX, ev.offsetY]); + } }} ON_mousemove={(ev: PointerEvent) => { + if (isInput) { + return; + } if (dragStart !== undefined) { if ( Math.sqrt( @@ -114,7 +125,7 @@ export const KanbanCard = (props: KanbanCardProps) => { type: 'card', offset: dragOffset, cardData: card, - prevColIdx:props.columnIdx + prevColIdx: props.columnIdx, }); console.log('offset', dragOffset); setDragStart(undefined); @@ -122,9 +133,8 @@ export const KanbanCard = (props: KanbanCardProps) => { } } }} - ON_mouseleave={() => { - setDragStart(undefined); - }} + ON_mouseleave={cancelDnd} + ON_mouseup={cancelDnd} > {activeBoard.myRole !== 'viewer' && (
{ initialText={card.title} cardId={card.id} onNewCard={(crd) => { + setDragStart(undefined); activeBoard.columns[props.columnIdx].cards = activeBoard.columns[ props.columnIdx ].cards.map((oldCard) => { @@ -177,7 +188,6 @@ export const KanbanCard = (props: KanbanCardProps) => { timer = setTimeout(() => { getCardDetails(card.id).then((val) => { setCardDetailsStore(val); - console.log(val); }); }, 300); }} diff --git a/src/components/KanbanColumn.tsx b/src/components/KanbanColumn.tsx index 97ebdd4..0802a3a 100644 --- a/src/components/KanbanColumn.tsx +++ b/src/components/KanbanColumn.tsx @@ -82,6 +82,9 @@ export const KanbanColumn = (props: KanbanColumnProps) => { ON_mouseleave={() => { setDragStart(undefined); }} + ON_mouseup={() => { + setDragStart(undefined); + }} >
{ cardPositions.push({ x: xCoord, diff --git a/src/utils/validation.ts b/src/utils/validation.ts index ed90e3b..0f86b9f 100644 --- a/src/utils/validation.ts +++ b/src/utils/validation.ts @@ -4,10 +4,19 @@ interface IValidationResult { } const EMAIL_ALLOWED_SYMBOLS = /[a-zA-Z0-9_.@-]*/; -const NICKNAME_ALLOWED_SYMBOLS = /[a-zA-Z0-9_.]*/; +const NICKNAME_ALLOWED_SYMBOLS = /^[a-zA-Z0-9_.]*$/; const EMAIL_REGEX = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i; +const hasUpperCase = /[A-Z]+/; + +const hasLowerCase = /[a-z]+/; + +const hasDigits = /\d+/; + +// eslint-disable-next-line no-useless-escape +const hasSpecialSymbol = /[!#&.,?/\\(){}\[\]"'`;:|<>*^%~]+/; + export const validateEmail = (email: string): IValidationResult => { if (email === '') { return { allowed: false, validationMessage: undefined }; @@ -53,15 +62,35 @@ export const validatePassword = (password: string): IValidationResult => { if (password === '') { return { allowed: false, validationMessage: undefined }; } - const validationMessage: string[] = []; - if (password.length < 8) { - validationMessage.push('должен быт не менее 8 символов'); - } + if (password.length > 50) { return { allowed: false, validationMessage: 'должен быть не более 50 символов', }; } + + const validationMessage: string[] = []; + if (password.length < 8) { + validationMessage.push('должен быть не менее 8 символов'); + } + if (!hasUpperCase.test(password) && !hasLowerCase.test(password)) { + validationMessage.push( + 'должен содержать заглавную и строчную латинские буквы' + ); + } else if (!hasUpperCase.test(password)) { + validationMessage.push('должен содержать заглавную латинскую букву'); + } else if (!hasLowerCase.test(password)) { + validationMessage.push('должен содержать строчную латинскую букву'); + } + if (!hasDigits.test(password)) { + validationMessage.push('должен содержать цифру'); + } + if (!hasSpecialSymbol.test(password)) { + validationMessage.push('должен содержать специальный символ'); + } + if (validationMessage) { + return { allowed: false, validationMessage: validationMessage.join(', ') }; + } return { allowed: true, validationMessage: undefined }; };