Skip to content

feat: UI–BLL Integration#50

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

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

Conversation

@kapitulin24
Copy link
Copy Markdown
Contributor

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
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
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

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, в плане ошибок, валидации и ре-рендеров

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