Skip to content

Commit

Permalink
fix: key validation in team and project creating forms
Browse files Browse the repository at this point in the history
  • Loading branch information
awinogradov committed Mar 5, 2023
1 parent e6e16b5 commit 4696e2e
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 34 deletions.
2 changes: 2 additions & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"Press key to create the team": "Press <key></key> to create the team.",
"Team with title already exists": "Team with title <b><title></title></b> already exists. Please, try to use another title.",
"Team with key already exists": "Team with key <b><key></key></b> already exists. Please, try to use another key.",
"Key must be 3 or longer characters": "Key must be 3 or longer characters",
"Perfect! Issues in your team will look like": "<b>Perfect!</b> Issues in your team will look like: <b>#<key></key>-42</b>, <b>#<key></key>-911</b>.",
"Flow": "Flow",
"Flow or state title": "Flow or state title"
Expand Down Expand Up @@ -73,6 +74,7 @@
"Press key to create the project": "Press <key></key> to create the project.",
"Project with key already exists": "Project with key <b><key></key></b> already exists. Please, try to use another key.",
"Perfect! Issues in your project will look like": "<b>Perfect!</b> Issues in your project will look like: <b>#<key></key>-42</b>, <b>#<key></key>-911</b>.",
"Key must be 3 or longer characters": "Key must be 3 or longer characters",
"Assign": "Assign",
"Enter name or email": "Enter name or email",
"Flow": "Flow",
Expand Down
2 changes: 2 additions & 0 deletions i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"Press key to create the team": "Нажми <key></key> чтобы создать команду.",
"Project with title already exists": "Команда с названием <b><title></title></b> уже существует. Попробуй другое.",
"Team with key already exists": "Команда с ключом <b><key></key></b> уже существует. Попробуй другой.",
"Key must be 3 or longer characters": "Ключ не может быть короче 3 символов",
"Perfect! Issues in your team will look like": "<b>Супер!</b> Задачи в твоей команде будут выглядеть примерно так: <b>#<key></key>-42</b>, <b>#<key></key>-911</b>.",
"Flow": "Флоу",
"Flow or state title": "Модель или статус"
Expand Down Expand Up @@ -72,6 +73,7 @@
"Press key to create the project": "Нажми <key></key> чтобы создать проект.",
"Project with key already exists": "Проект с ключом <b><key></key></b> уже существует. Попробуйте любой другой.",
"Perfect! Issues in your project will look like": "<b>Супер!</b> Задачи в вашем проекте будут выглядеть примерно так: <b>#<key></key>-42</b>, <b>#<key></key>-911</b>.",
"Key must be 3 or longer characters": "Ключ не может быть короче 3 символов",
"Assign": "Ответственный",
"Enter name or email": "Имя или почта",
"Flow": "Флоу",
Expand Down
38 changes: 24 additions & 14 deletions src/components/ProjectCreateForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const ProjectCreateForm: React.FC = () => {
const [focusedInput, setFocusedInput] = useState(false);
const [hoveredInput, setHoveredInput] = useState(false);
const [busy, setBusy] = useState(false);
const [dirtyKey, setDirtyKey] = useState(false);

const schema = createProjectSchemaProvider(t);
type ProjectFormType = z.infer<typeof schema>;
Expand Down Expand Up @@ -117,14 +118,18 @@ const ProjectCreateForm: React.FC = () => {

useDebouncedEffect(
() => {
setValue('key', titleWatcher && titleWatcher !== '' ? keyPredictor(titleWatcher) : '');
if (!dirtyKey && titleWatcher && titleWatcher !== '') {
setValue('key', keyPredictor(titleWatcher));
}
},
300,
[setValue, titleWatcher],
);

const isKeyEnoughLength = Boolean(keyWatcher?.length >= 3);
const { data: flowData } = useSWR('flow', () => flowFetcher(user));
const { data: projectData } = useSWR(keyWatcher && keyWatcher !== '' ? [user, keyWatcher] : null, projectFetcher);
const { data: projectData } = useSWR(isKeyEnoughLength ? [user, keyWatcher] : null, projectFetcher);
const isKeyUnique = Boolean(projectData?.project === null || !projectData);

useEffect(() => {
if (flowData?.flowRecommended) {
Expand All @@ -145,7 +150,10 @@ const ProjectCreateForm: React.FC = () => {
[router, createProject, t],
);

const isProjectKeyAvailable = Boolean(projectData?.project === null || !projectData);
const onKeyDirty = useCallback(() => {
setDirtyKey(true);
}, []);

const richProps = {
b: (c: React.ReactNode) => (
<Text as="span" size="s" weight="bolder">
Expand All @@ -155,14 +163,21 @@ const ProjectCreateForm: React.FC = () => {
key: () => keyWatcher,
};

// eslint-disable-next-line no-nested-ternary
const tooltip = isKeyEnoughLength
? isKeyUnique
? t.rich('create.Perfect! Issues in your project will look like', richProps)
: t.rich('create.Project with key already exists', richProps)
: t('create.Key must be 3 or longer characters');

return (
<>
<ModalHeader>
<FormTitle>{t('create.Create new project')}</FormTitle>
</ModalHeader>

<ModalContent>
<Form onSubmit={handleSubmit(onCreateProject)} submitHotkey={submitKeys}>
<Form onSubmit={isKeyUnique ? handleSubmit(onCreateProject) : undefined} submitHotkey={submitKeys}>
<StyledProjectTitleContainer>
<FormInput
{...register('title')}
Expand Down Expand Up @@ -190,15 +205,10 @@ const ProjectCreateForm: React.FC = () => {
>
<KeyInput
disabled={busy}
available={isProjectKeyAvailable}
tooltip={
isProjectKeyAvailable
? t.rich(
'create.Perfect! Issues in your project will look like',
richProps,
)
: t.rich('create.Project with key already exists', richProps)
}
available={isKeyUnique && isKeyEnoughLength}
tooltip={tooltip}
onDirty={onKeyDirty}
error={errorsResolver('key')}
{...field}
/>
</StyledProjectKeyInputContainer>
Expand Down Expand Up @@ -236,7 +246,7 @@ const ProjectCreateForm: React.FC = () => {
<Button
view="primary"
disabled={busy}
outline={!isValid}
outline={!isValid || !isKeyUnique || !isKeyEnoughLength}
type="submit"
text={t('create.Create project')}
/>
Expand Down
49 changes: 29 additions & 20 deletions src/components/TeamCreateForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslations } from 'next-intl';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
Expand Down Expand Up @@ -47,15 +47,14 @@ const flowFetcher = createFetcher(() => ({
},
},
}));
const teamsFetcher = createFetcher((_, title: string) => ({
teams: [
const teamsFetcher = createFetcher((_, key: string) => ({
team: [
{
data: {
title,
},
key,
},
{
title: true,
key: true,
},
],
}));
Expand Down Expand Up @@ -111,6 +110,7 @@ const TeamCreateForm: React.FC = () => {
const [focusedInput, setFocusedInput] = useState(false);
const [hoveredInput, setHoveredInput] = useState(false);
const [busy, setBusy] = useState(false);
const [dirtyKey, setDirtyKey] = useState(false);

const schema = schemaProvider(t);

Expand Down Expand Up @@ -139,14 +139,18 @@ const TeamCreateForm: React.FC = () => {

useDebouncedEffect(
() => {
setValue('key', titleWatcher && titleWatcher !== '' ? keyPredictor(titleWatcher) : '');
if (!dirtyKey && titleWatcher && titleWatcher !== '') {
setValue('key', keyPredictor(titleWatcher));
}
},
300,
[setValue, titleWatcher],
);

const isKeyEnoughLength = Boolean(keyWatcher?.length >= 3);
const { data: flowData } = useSWR('flow', () => flowFetcher(user));
const { data: teamsData } = useSWR(titleWatcher && titleWatcher !== '' ? [user, titleWatcher] : null, teamsFetcher);
const { data: teamsData } = useSWR(isKeyEnoughLength ? [user, keyWatcher] : null, teamsFetcher);
const isKeyUnique = !teamsData?.team;

useEffect(() => {
if (flowData?.flowRecommended) {
Expand Down Expand Up @@ -185,7 +189,10 @@ const TeamCreateForm: React.FC = () => {
dispatchModalEvent(ModalEvent.TeamCreateModal)();
};

const isTeamTitleAvailable = Boolean(teamsData?.teams?.length === 0);
const onKeyDirty = useCallback(() => {
setDirtyKey(true);
}, []);

const richProps = {
b: (c: React.ReactNode) => (
<Text as="span" size="s" weight="bolder">
Expand All @@ -195,14 +202,21 @@ const TeamCreateForm: React.FC = () => {
key: () => keyWatcher,
};

// eslint-disable-next-line no-nested-ternary
const tooltip = isKeyEnoughLength
? isKeyUnique
? t.rich('Perfect! Issues in your team will look like', richProps)
: t.rich('Team with key already exists', richProps)
: t('Key must be 3 or longer characters');

return (
<>
<ModalHeader>
<FormTitle>{t('Create new team')}</FormTitle>
</ModalHeader>

<ModalContent>
<Form onSubmit={handleSubmit(createTeam)} submitHotkey={submitKeys}>
<Form onSubmit={isKeyUnique ? handleSubmit(createTeam) : undefined} submitHotkey={submitKeys}>
<StyledTitleContainer>
<FormInput
{...register('title')}
Expand Down Expand Up @@ -230,15 +244,10 @@ const TeamCreateForm: React.FC = () => {
>
<KeyInput
disabled={busy}
available={isTeamTitleAvailable}
tooltip={
isTeamTitleAvailable
? t.rich(
'Perfect! Issues in your team will look like',
richProps,
)
: t.rich('Team with key already exists', richProps)
}
available={isKeyUnique && isKeyEnoughLength}
tooltip={tooltip}
onDirty={onKeyDirty}
error={errorsResolver('key')}
{...field}
/>
</StyledTeamKeyInputContainer>
Expand Down Expand Up @@ -276,7 +285,7 @@ const TeamCreateForm: React.FC = () => {
<Button
view="primary"
disabled={busy}
outline={!isValid}
outline={!isValid || !isKeyUnique || !isKeyEnoughLength}
type="submit"
text={t('Create team')}
/>
Expand Down

0 comments on commit 4696e2e

Please sign in to comment.