Skip to content

feat: UI–BLL Integration#50

Open
kapitulin24 wants to merge 28 commits into
devfrom
feat/ui-bll-integration
Open

feat: UI–BLL Integration#50
kapitulin24 wants to merge 28 commits into
devfrom
feat/ui-bll-integration

Conversation

@kapitulin24
Copy link
Copy Markdown
Contributor

@kapitulin24 kapitulin24 commented May 17, 2026

feat: UI–BLL Integration

Ветка интегрирует фронтенд с реальным API и завершает построение ключевых фич продукта.

Что сделано

Teams — полный CRUD

  • Создание команды, приглашение участников, удаление с диалогом подтверждения
  • Переключение активной команды через Zustand-стор (createStore factory + team slug store)
  • Управление участниками: роли, статусы, карточки с select-компонентами и скелетонами загрузки
  • Управление приглашениями: список, смена роли, отзыв приглашения

Team Settings — реальное API

  • Форма настроек переведена на react-hook-form + TanStack Query (вместо моков)
  • Загрузка обложки команды, настройки идентичности (название, слаг), секция безопасности приглашений, Danger Zone

Profile — вкладка Teams

  • Разделены UI для команд и приглашений
  • Добавлены mutation-хуки для профиля

Layout & Sidebar

  • Добавлен SidebarLayout, модуль сайдбара переработан с плоской структурой
  • Команды-переключатель заменён на TeamsDropdown
  • Извлечён виджет TabsNav

Entities & Shared

  • Обновлены схемы и типы для team и user, добавлен UserAvatar, SlugField
  • Структурированы URL аватаров команды (без слага в путях приглашений)
  • createStore factory с автогенерацией селекторов
  • Переименование invite → invitation по всей кодовой базе
  • Переименование entity file → asset

Theme

  • Глобальная палитра переведена на OKLCH, токены сайдбара выровнены

Infra

  • Добавлены env-переменные для Imagor в infra/dev/.env.example

Проверка

  • Создание команды и переключение между командами
  • Приглашение / удаление участника
  • Смена роли и статуса участника
  • Сохранение настроек команды (форма)
  • Вкладка Teams на странице профиля
  • Скелетоны и состояния загрузки

@kapitulin24 kapitulin24 requested a review from soorq May 17, 2026 21:29
@kapitulin24 kapitulin24 added frontend backend-integration features User scenarios and sliced features labels May 17, 2026
@github-actions github-actions Bot added devops ui-kit Shared UI components, styles and storybook core-logic Global providers, api instances and core shared libs labels May 17, 2026
@github-actions github-actions Bot added domain Business entities and models views Pages, widgets and layouts dependencies Dependency updates (package.json, pnpm-lock) labels May 17, 2026
perekljuchatel
perekljuchatel previously approved these changes May 18, 2026
perekljuchatel
perekljuchatel previously approved these changes May 18, 2026
Copy link
Copy Markdown
Member

@perekljuchatel perekljuchatel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/entities/team/config/roles.ts Outdated
Comment thread src/entities/user/api/queries.ts
Comment thread src/pages/profile/ui/teams-page/Invitations.tsx
export function useTeamHotkeys(teams: TUser.UserTeamResponse[], onSelect: (slug: string) => void) {
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (!(e.metaKey || e.ctrlKey)) return;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А там не через бинд E20/E32 кнопки и тп?
Я чего-то видать упустил =D

Comment thread src/entities/team/ui/SlugField.tsx Outdated
Comment thread src/entities/team/ui/SlugField.tsx Outdated

const debouncedCheckSlug = useMemo(() => debounce((fn: typeof refetch) => fn(), 400), []);

useEffect(() => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хук опасный по депенденси

Внешние ссылки, старое замыкание и новые баги, что либо в бесконечный цикл уйдет, либо ошибку на клиента отдаст голую

Если у тебя на форме стоит условие criteriaMode: onBlur - ок, такого, вроде не должно быть

Вариант 1

   const id = useId();
    const { field, fieldState, formState } = useController(props);
  
  const slug = (field.value as string) ?? '';
  const defaultSlug = (formState.defaultValues?.[props.name] as string | undefined) ?? '';
  const isDirty = fieldState.isDirty;

  // React Query должен реагировать на изменение slug автоматически, но с условием enabled
  const { data, isFetching } = useQuery({
    ...TeamQueries.checkSlug(slug),
    // Запрос идет только если поле изменилось, оно не пустое и длиннее 1 символа
    enabled: isDirty && slug.trim().length > 1 && slug !== defaultSlug,
  });

  // Синхронизация ошибок API с состоянием формы
  useEffect(() => {
    if (!isDirty || !slug) {
      clearErrors(props.name);
      return;
    }

    if (data?.available === false) {
      setError(props.name, { 
        type: 'validate',
        message: data.message ?? 'Этот адрес уже занят' 
      });
    } else if (data?.available === true) {
      clearErrors(props.name);
    }
  }, [data, isDirty, slug, props.name, setError, clearErrors]);

  const showStatus = isDirty && !!slug && slug !== defaultSlug;

Вариант 2

const id = useId();

const { field, fieldState } = useController({
    ...props,
    rules: {
      validate: () => {
        if (fieldState.isDirty && data?.available === false) {
          return data.message ?? 'Этот адрес уже занят';
        }
        return true;
      }
    }
  });

const slug = (field.value as string) ?? '';

  const { data, isFetching, refetch } = useQuery({
    ...TeamQueries.checkSlug(slug),
    enabled: fieldState.isDirty && slug.length > 1,
  });

useEffect(() => {
    if (data) {
      field.onBlur(); // Заставляет пересчитать rules.validate
    }
  }, [data]);

Copy link
Copy Markdown
Collaborator

@soorq soorq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавил еще, где упустил

Comment thread src/features/teams/active-team/model/useTeamsQueryWithSlugSync.ts
import { useCreateTeam, type UseCreateTeamOptions } from './useCreateTeam';

export function useCreateTeamForm(mutateOptions: UseCreateTeamOptions = {}) {
const form = useForm<CreateTeamFormValues>({
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://react-hook-form.com/docs/useform
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit' - почитай, как и кто что делает

https://react-hook-form.com/docs/useform#reValidateMode
reValidateMode: onChange | onBlur | onSubmit = 'onChange' - почитай, как и кто что делает

https://react-hook-form.com/docs/useform#criteriaMode
criteriaMode: firstError | all - лучше до первой ошибки

https://react-hook-form.com/docs/useform#resetOptions

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это база, что улучшить ux, в плане ошибок, валидации и ре-рендеров

resolver: useZodValidationWithAsyncCheck(TeamSettingsFormSchema, (...args) =>
validateTeamSlugAsync(checkSlug, ...args)
),
mode: 'onChange',
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лучше onBlur

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend-integration core-logic Global providers, api instances and core shared libs dependencies Dependency updates (package.json, pnpm-lock) devops domain Business entities and models features User scenarios and sliced features frontend ui-kit Shared UI components, styles and storybook views Pages, widgets and layouts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Связать UI teams с бизнес-логикой и убрать runtime-моки

3 participants