diff --git a/.prettierrc.mjs b/.prettierrc.mjs index c09cbcef..23666d92 100644 --- a/.prettierrc.mjs +++ b/.prettierrc.mjs @@ -9,6 +9,12 @@ const config = { '', '^@repo(.*)$', '', + '^@/views(.*)$', + '^@/widgets(.*)$', + '^@/features(.*)$', + '^@/entities(.*)$', + '^@/shared(.*)$', + '', '^[../]', '^[./]', ], diff --git a/apps/web/app/(auth)/layout.tsx b/apps/web/app/(auth)/layout.tsx index f0832d70..8051227c 100644 --- a/apps/web/app/(auth)/layout.tsx +++ b/apps/web/app/(auth)/layout.tsx @@ -1,8 +1,8 @@ -import { FEATURES } from '@/hooks/use-feature-flag' -import { ROUTES } from '@/shared/config/routes' import Link from 'next/link' import { notFound } from 'next/navigation' +import { FEATURES, ROUTES } from '@/shared/config' + interface Props { children: React.ReactNode } diff --git a/apps/web/app/(auth)/login/page.tsx b/apps/web/app/(auth)/login/page.tsx index 1b8930d9..d75d88cd 100644 --- a/apps/web/app/(auth)/login/page.tsx +++ b/apps/web/app/(auth)/login/page.tsx @@ -1,66 +1,5 @@ -'use client' - -import { useLogin } from '@/hooks/api/use-auth' -import { isApiError } from '@/lib/api/utils' -import { ROUTES } from '@/shared/config/routes' -import Link from 'next/link' -import { useRouter } from 'next/navigation' - -import { Button, Form, toast } from '@repo/ui' - -import { AuthFormLayout } from '../auth-form-layout' -import { LoginForm } from './login-form' -import { LoginFormValues, useLoginForm } from './use-login-form' +import { LoginPageView } from '@/views/auth' export default function LoginPage() { - const form = useLoginForm() - - const loginMutation = useLogin() - const router = useRouter() - - const onSubmit = async (data: LoginFormValues) => { - try { - await loginMutation.mutateAsync(data) - router.push(ROUTES.teams) - } catch (error) { - if (isApiError(error)) { - toast.error(error.message) - } else { - throw error - } - } - } - - return ( -
- - - Войти - - } - > -
- -

- Еще нет аккаунта?{' '} - - Зарегистрироваться - -

-
-
-
- - ) + return } diff --git a/apps/web/app/(auth)/register/page.tsx b/apps/web/app/(auth)/register/page.tsx index c883890a..16b13f29 100644 --- a/apps/web/app/(auth)/register/page.tsx +++ b/apps/web/app/(auth)/register/page.tsx @@ -1,66 +1,5 @@ -'use client' - -import { useRegister } from '@/hooks/api/use-auth' -import { isApiError } from '@/lib/api/utils' -import { ROUTES } from '@/shared/config/routes' -import Link from 'next/link' -import { useRouter } from 'next/navigation' - -import { Button, Form, toast } from '@repo/ui' - -import { AuthFormLayout } from '../auth-form-layout' -import { RegisterForm } from './register-form' -import { RegisterFormValues, useRegisterForm } from './use-register-form' +import { RegisterPageView } from '@/views/auth' export default function RegisterPage() { - const form = useRegisterForm() - - const registerMutation = useRegister() - const router = useRouter() - - const onSubmit = async (data: RegisterFormValues) => { - try { - await registerMutation.mutateAsync(data) - router.push(ROUTES.teams) - } catch (error) { - if (isApiError(error)) { - toast.error(error.message) - } else { - throw error - } - } - } - - return ( -
- - - Зарегистрироваться - - } - > -
- -

- Уже есть аккаунт?{' '} - - Войти - -

-
-
-
- - ) + return } diff --git a/apps/web/app/(dashboard)/layout.tsx b/apps/web/app/(dashboard)/layout.tsx index 1f689d7b..80d614ff 100644 --- a/apps/web/app/(dashboard)/layout.tsx +++ b/apps/web/app/(dashboard)/layout.tsx @@ -1,15 +1,38 @@ +import { dehydrate, HydrationBoundary } from '@tanstack/react-query' +import { redirect } from 'next/navigation' + import { MainLayout } from '@/widgets/main-layout' +import { authKeys } from '@/shared/api/use-auth' +import { ROUTES } from '@/shared/config' +import { authService } from '@/shared/lib/api/auth-service' +import { isApiError } from '@/shared/lib/api/utils' +import { getQueryClient } from '@/shared/lib/query-client' interface Props { children: React.ReactNode modal: React.ReactNode } -export default function DashboardLayout({ children, modal }: Props) { +export default async function DashboardLayout({ children, modal }: Props) { + const queryClient = getQueryClient() + + try { + await queryClient.prefetchQuery({ + queryKey: authKeys.getMe, + queryFn: authService.getMe, + }) + } catch (error) { + if (isApiError(error) && error.statusCode === 401) { + redirect(ROUTES.login) + } + + throw error + } + return ( - <> + {children} {modal} - + ) } diff --git a/apps/web/app/(dashboard)/sprints/page.tsx b/apps/web/app/(dashboard)/sprints/page.tsx index 5a35bf11..34b78e60 100644 --- a/apps/web/app/(dashboard)/sprints/page.tsx +++ b/apps/web/app/(dashboard)/sprints/page.tsx @@ -1,8 +1,9 @@ -import { FEATURES } from '@/hooks/use-feature-flag' import { notFound } from 'next/navigation' import { Card, CardContent } from '@repo/ui' +import { FEATURES } from '@/shared/config' + type SprintTask = { id: string title: string diff --git a/apps/web/app/(dashboard)/tasks/page.tsx b/apps/web/app/(dashboard)/tasks/page.tsx index 6cf7dfa7..dd00b9ca 100644 --- a/apps/web/app/(dashboard)/tasks/page.tsx +++ b/apps/web/app/(dashboard)/tasks/page.tsx @@ -1,8 +1,9 @@ -import { FEATURES } from '@/hooks/use-feature-flag' import { notFound } from 'next/navigation' import { Button } from '@repo/ui' +import { FEATURES } from '@/shared/config' + const mockTasks = [ { id: 'TT-1', diff --git a/apps/web/app/(dashboard)/teams/[id]/projects/[projectId]/page.tsx b/apps/web/app/(dashboard)/teams/[id]/projects/[projectId]/page.tsx index b1f80ff8..9dfc63db 100644 --- a/apps/web/app/(dashboard)/teams/[id]/projects/[projectId]/page.tsx +++ b/apps/web/app/(dashboard)/teams/[id]/projects/[projectId]/page.tsx @@ -1,7 +1,8 @@ -import { FEATURES } from '@/hooks/use-feature-flag' -import { ProjectDetailPageView } from '@/views/projects' import { notFound } from 'next/navigation' +import { ProjectDetailPageView } from '@/views/projects' +import { FEATURES } from '@/shared/config' + export default function ProjectDetailPage() { if (!FEATURES.PROJECTS) { notFound() diff --git a/apps/web/app/(dashboard)/teams/[id]/projects/page.tsx b/apps/web/app/(dashboard)/teams/[id]/projects/page.tsx index 3df15731..ecb9f9d3 100644 --- a/apps/web/app/(dashboard)/teams/[id]/projects/page.tsx +++ b/apps/web/app/(dashboard)/teams/[id]/projects/page.tsx @@ -1,7 +1,8 @@ -import { FEATURES } from '@/hooks/use-feature-flag' -import { ProjectsPageView } from '@/views/projects' import { notFound } from 'next/navigation' +import { ProjectsPageView } from '@/views/projects' +import { FEATURES } from '@/shared/config' + export default function ProjectsPage() { if (!FEATURES.PROJECTS) { notFound() diff --git a/apps/web/app/(dashboard)/teams/[id]/settings/page.tsx b/apps/web/app/(dashboard)/teams/[id]/settings/page.tsx index 867d6fb2..37cc59ec 100644 --- a/apps/web/app/(dashboard)/teams/[id]/settings/page.tsx +++ b/apps/web/app/(dashboard)/teams/[id]/settings/page.tsx @@ -1,7 +1,8 @@ -import { FEATURES } from '@/hooks/use-feature-flag' -import { TeamSettingsPageView } from '@/views/teams' import { notFound } from 'next/navigation' +import { TeamSettingsPageView } from '@/views/teams' +import { FEATURES } from '@/shared/config' + export default function TeamSettingsPage() { if (!FEATURES.TEAM_SETTINGS) { notFound() diff --git a/apps/web/app/error.tsx b/apps/web/app/error.tsx index 09e16aa5..15821203 100644 --- a/apps/web/app/error.tsx +++ b/apps/web/app/error.tsx @@ -1,11 +1,12 @@ 'use client' -import { ROUTES } from '@/shared/config/routes' import Link from 'next/link' import { useEffect } from 'react' import { Button, EmptyState } from '@repo/ui' +import { ROUTES } from '@/shared/config' + type GlobalErrorProps = { error: Error & { digest?: string } reset: () => void diff --git a/apps/web/app/not-found.tsx b/apps/web/app/not-found.tsx index f0afa265..f937f9d9 100644 --- a/apps/web/app/not-found.tsx +++ b/apps/web/app/not-found.tsx @@ -1,8 +1,9 @@ -import { ROUTES } from '@/shared/config/routes' import Link from 'next/link' import { Button, EmptyState } from '@repo/ui' +import { ROUTES } from '@/shared/config' + export default function GlobalNotFound() { return (
diff --git a/apps/web/app/providers.tsx b/apps/web/app/providers.tsx index 7e2dc72d..ab1d12b0 100644 --- a/apps/web/app/providers.tsx +++ b/apps/web/app/providers.tsx @@ -1,10 +1,10 @@ 'use client' -import { ThemeSync } from '@/features/theme' import { QueryClientProvider } from '@tanstack/react-query' import { ReactQueryDevtools } from '@tanstack/react-query-devtools' -import { getQueryClient } from '../lib/query-client' +import { ThemeSync } from '@/features/theme' +import { getQueryClient } from '@/shared/lib/query-client' interface Props { children: React.ReactNode diff --git a/apps/web/features/theme/ui/theme-sync.tsx b/apps/web/features/theme/ui/theme-sync.tsx index 7a81c2a8..44f30a89 100644 --- a/apps/web/features/theme/ui/theme-sync.tsx +++ b/apps/web/features/theme/ui/theme-sync.tsx @@ -2,7 +2,8 @@ import { useEffect } from 'react' -import { useHydratedStore } from '../../../shared/hooks' +import { useHydratedStore } from '@/shared/hooks' + import { useThemeStore } from '../model/store' function ThemeSync() { diff --git a/apps/web/features/theme/ui/theme-toggle.tsx b/apps/web/features/theme/ui/theme-toggle.tsx index 5846eeca..fbba1207 100644 --- a/apps/web/features/theme/ui/theme-toggle.tsx +++ b/apps/web/features/theme/ui/theme-toggle.tsx @@ -2,7 +2,8 @@ import { Button, cn, MoonIcon, SunIcon } from '@repo/ui' -import { useHydratedStore } from '../../../shared/hooks' +import { useHydratedStore } from '@/shared/hooks' + import { useThemeStore } from '../model/store' interface ThemeToggleProps { diff --git a/apps/web/proxy.ts b/apps/web/proxy.ts index f6ad920a..1dbb0042 100644 --- a/apps/web/proxy.ts +++ b/apps/web/proxy.ts @@ -1,17 +1,17 @@ +import { NextResponse, type NextRequest, type ProxyConfig } from 'next/server' + import { isAuthRoute, isProtectedRoute, ROUTE_QUERY_PARAMS, ROUTES, -} from '@/shared/config/routes' -import { NextResponse, type NextRequest, type ProxyConfig } from 'next/server' - -import { appendSetCookieHeaders, clearAuthCookies } from './lib/api/auth-cookies' +} from '@/shared/config' +import { appendSetCookieHeaders, clearAuthCookies } from '@/shared/lib/api/auth-cookies' import { refreshAuthSession, type AuthRefreshResult, -} from './lib/api/refresh-auth-session' -import { isTokenExpiredSoon } from './lib/session' +} from '@/shared/lib/api/refresh-auth-session' +import { isTokenExpiredSoon } from '@/shared/lib/session' const createLoginRedirect = (request: NextRequest) => { const { pathname, search } = request.nextUrl diff --git a/apps/web/hooks/api/use-auth.ts b/apps/web/shared/api/use-auth.ts similarity index 91% rename from apps/web/hooks/api/use-auth.ts rename to apps/web/shared/api/use-auth.ts index c9bbaac0..51dfc037 100644 --- a/apps/web/hooks/api/use-auth.ts +++ b/apps/web/shared/api/use-auth.ts @@ -1,6 +1,7 @@ -import { authService } from '@/lib/api/auth-service' import { useMutation, useQuery } from '@tanstack/react-query' +import { authService } from '@/shared/lib/api/auth-service' + export const authKeys = { register: ['register'], login: ['login'], diff --git a/apps/web/hooks/api/use-example.ts b/apps/web/shared/api/use-example.ts similarity index 95% rename from apps/web/hooks/api/use-example.ts rename to apps/web/shared/api/use-example.ts index 712eec29..3486246c 100644 --- a/apps/web/hooks/api/use-example.ts +++ b/apps/web/shared/api/use-example.ts @@ -10,8 +10,8 @@ import { Example, exampleService, UpdateExampleDto, -} from '../../lib/api/example-service' -import { ApiError, PaginationParams } from '../../lib/api/types' +} from '@/shared/lib/api/example-service' +import { ApiError, PaginationParams } from '@/shared/lib/api/types' // Query keys для кэширования export const exampleKeys = { diff --git a/apps/web/hooks/api/use-teams.ts b/apps/web/shared/api/use-teams.ts similarity index 95% rename from apps/web/hooks/api/use-teams.ts rename to apps/web/shared/api/use-teams.ts index aedd8ad2..e81c052e 100644 --- a/apps/web/hooks/api/use-teams.ts +++ b/apps/web/shared/api/use-teams.ts @@ -1,12 +1,13 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' + import { teamsService, type CreateTeam, type DeleteTeamResponse, type Team, type UpdateTeam, -} from '@/lib/api/teams-service' -import type { ApiError } from '@/lib/api/types' -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +} from '@/shared/lib/api/teams-service' +import type { ApiError } from '@/shared/lib/api/types' export const teamsKeys = { all: ['teams'] as const, diff --git a/apps/web/hooks/use-feature-flag.ts b/apps/web/shared/config/feature-flags.ts similarity index 100% rename from apps/web/hooks/use-feature-flag.ts rename to apps/web/shared/config/feature-flags.ts diff --git a/apps/web/shared/config/index.ts b/apps/web/shared/config/index.ts new file mode 100644 index 00000000..0bcf4b99 --- /dev/null +++ b/apps/web/shared/config/index.ts @@ -0,0 +1,2 @@ +export * from './feature-flags' +export * from './routes' diff --git a/apps/web/lib/api/auth-cookies.ts b/apps/web/shared/lib/api/auth-cookies.ts similarity index 100% rename from apps/web/lib/api/auth-cookies.ts rename to apps/web/shared/lib/api/auth-cookies.ts diff --git a/apps/web/lib/api/auth-service.ts b/apps/web/shared/lib/api/auth-service.ts similarity index 100% rename from apps/web/lib/api/auth-service.ts rename to apps/web/shared/lib/api/auth-service.ts diff --git a/apps/web/lib/api/axios-config.ts b/apps/web/shared/lib/api/axios-config.ts similarity index 100% rename from apps/web/lib/api/axios-config.ts rename to apps/web/shared/lib/api/axios-config.ts diff --git a/apps/web/lib/api/client.ts b/apps/web/shared/lib/api/client.ts similarity index 92% rename from apps/web/lib/api/client.ts rename to apps/web/shared/lib/api/client.ts index e90b32a9..ba1d4ddf 100644 --- a/apps/web/lib/api/client.ts +++ b/apps/web/shared/lib/api/client.ts @@ -1,10 +1,11 @@ -import { ROUTE_QUERY_PARAMS, ROUTES } from '@/shared/config/routes' import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios' +import { ROUTE_QUERY_PARAMS, ROUTES } from '@/shared/config' + import { isClientSide, setCookieHeader } from './auth-cookies' import { axiosConfig } from './axios-config' import { refreshAuthSession } from './refresh-auth-session' -import { ApiError } from './types' +import type { ApiError } from './types' import { toApiError } from './utils' type RetryableConfig = InternalAxiosRequestConfig & { diff --git a/apps/web/lib/api/example-service.ts b/apps/web/shared/lib/api/example-service.ts similarity index 100% rename from apps/web/lib/api/example-service.ts rename to apps/web/shared/lib/api/example-service.ts diff --git a/apps/web/lib/api/public-client.ts b/apps/web/shared/lib/api/public-client.ts similarity index 100% rename from apps/web/lib/api/public-client.ts rename to apps/web/shared/lib/api/public-client.ts diff --git a/apps/web/lib/api/refresh-auth-session.ts b/apps/web/shared/lib/api/refresh-auth-session.ts similarity index 100% rename from apps/web/lib/api/refresh-auth-session.ts rename to apps/web/shared/lib/api/refresh-auth-session.ts diff --git a/apps/web/lib/api/request-auth-refresh.ts b/apps/web/shared/lib/api/request-auth-refresh.ts similarity index 100% rename from apps/web/lib/api/request-auth-refresh.ts rename to apps/web/shared/lib/api/request-auth-refresh.ts diff --git a/apps/web/lib/api/teams-service.ts b/apps/web/shared/lib/api/teams-service.ts similarity index 100% rename from apps/web/lib/api/teams-service.ts rename to apps/web/shared/lib/api/teams-service.ts diff --git a/apps/web/lib/api/types.ts b/apps/web/shared/lib/api/types.ts similarity index 100% rename from apps/web/lib/api/types.ts rename to apps/web/shared/lib/api/types.ts diff --git a/apps/web/lib/api/utils.ts b/apps/web/shared/lib/api/utils.ts similarity index 100% rename from apps/web/lib/api/utils.ts rename to apps/web/shared/lib/api/utils.ts diff --git a/apps/web/lib/projects/catalog.ts b/apps/web/shared/lib/projects/catalog.ts similarity index 98% rename from apps/web/lib/projects/catalog.ts rename to apps/web/shared/lib/projects/catalog.ts index f08c59f1..29381501 100644 --- a/apps/web/lib/projects/catalog.ts +++ b/apps/web/shared/lib/projects/catalog.ts @@ -1,4 +1,4 @@ -import { teamRoutes } from '@/shared/config/routes' +import { teamRoutes } from '@/shared/config' export type ProjectCatalogItem = { id: string diff --git a/apps/web/shared/lib/projects/index.ts b/apps/web/shared/lib/projects/index.ts new file mode 100644 index 00000000..6f5c1d90 --- /dev/null +++ b/apps/web/shared/lib/projects/index.ts @@ -0,0 +1,2 @@ +export * from './catalog' +export * from './project-code' diff --git a/apps/web/lib/projects/project-code.ts b/apps/web/shared/lib/projects/project-code.ts similarity index 100% rename from apps/web/lib/projects/project-code.ts rename to apps/web/shared/lib/projects/project-code.ts diff --git a/apps/web/lib/query-client.ts b/apps/web/shared/lib/query-client.ts similarity index 100% rename from apps/web/lib/query-client.ts rename to apps/web/shared/lib/query-client.ts diff --git a/apps/web/lib/session/index.ts b/apps/web/shared/lib/session/index.ts similarity index 100% rename from apps/web/lib/session/index.ts rename to apps/web/shared/lib/session/index.ts diff --git a/apps/web/lib/session/utils.ts b/apps/web/shared/lib/session/utils.ts similarity index 100% rename from apps/web/lib/session/utils.ts rename to apps/web/shared/lib/session/utils.ts diff --git a/apps/web/views/auth/index.ts b/apps/web/views/auth/index.ts new file mode 100644 index 00000000..e1d9e759 --- /dev/null +++ b/apps/web/views/auth/index.ts @@ -0,0 +1,2 @@ +export { LoginPageView } from './ui/login-page-view' +export { RegisterPageView } from './ui/register-page-view' diff --git a/apps/web/app/(auth)/login/use-login-form.ts b/apps/web/views/auth/model/use-login-form.ts similarity index 100% rename from apps/web/app/(auth)/login/use-login-form.ts rename to apps/web/views/auth/model/use-login-form.ts diff --git a/apps/web/app/(auth)/register/use-register-form.ts b/apps/web/views/auth/model/use-register-form.ts similarity index 100% rename from apps/web/app/(auth)/register/use-register-form.ts rename to apps/web/views/auth/model/use-register-form.ts diff --git a/apps/web/app/(auth)/auth-form-layout.tsx b/apps/web/views/auth/ui/auth-form-layout.tsx similarity index 100% rename from apps/web/app/(auth)/auth-form-layout.tsx rename to apps/web/views/auth/ui/auth-form-layout.tsx diff --git a/apps/web/app/(auth)/login/login-form.tsx b/apps/web/views/auth/ui/login-form.tsx similarity index 93% rename from apps/web/app/(auth)/login/login-form.tsx rename to apps/web/views/auth/ui/login-form.tsx index ce59e409..8f5d093e 100644 --- a/apps/web/app/(auth)/login/login-form.tsx +++ b/apps/web/views/auth/ui/login-form.tsx @@ -12,7 +12,7 @@ import { VStack, } from '@repo/ui' -import { LoginFormValues } from './use-login-form' +import type { LoginFormValues } from '../model/use-login-form' const LoginForm = () => { const { control } = useFormContext() diff --git a/apps/web/views/auth/ui/login-page-view.tsx b/apps/web/views/auth/ui/login-page-view.tsx new file mode 100644 index 00000000..1d6af186 --- /dev/null +++ b/apps/web/views/auth/ui/login-page-view.tsx @@ -0,0 +1,69 @@ +'use client' + +import Link from 'next/link' +import { useRouter } from 'next/navigation' + +import { Button, Form, toast } from '@repo/ui' + +import { useLogin } from '@/shared/api/use-auth' +import { ROUTES } from '@/shared/config' +import { isApiError } from '@/shared/lib/api/utils' + +import { useLoginForm, type LoginFormValues } from '../model/use-login-form' +import { AuthFormLayout } from './auth-form-layout' +import { LoginForm } from './login-form' + +function LoginPageView() { + const form = useLoginForm() + + const loginMutation = useLogin() + const router = useRouter() + + const onSubmit = async (data: LoginFormValues) => { + try { + await loginMutation.mutateAsync(data) + router.push(ROUTES.teams) + } catch (error) { + if (isApiError(error)) { + toast.error(error.message) + } else { + throw error + } + } + } + + return ( +
+ + + Войти + + } + > +
+ +

+ Еще нет аккаунта?{' '} + + Зарегистрироваться + +

+
+
+
+ + ) +} + +export { LoginPageView } diff --git a/apps/web/app/(auth)/register/register-form.tsx b/apps/web/views/auth/ui/register-form.tsx similarity index 95% rename from apps/web/app/(auth)/register/register-form.tsx rename to apps/web/views/auth/ui/register-form.tsx index 3716b06a..a620ca94 100644 --- a/apps/web/app/(auth)/register/register-form.tsx +++ b/apps/web/views/auth/ui/register-form.tsx @@ -12,7 +12,7 @@ import { VStack, } from '@repo/ui' -import { RegisterFormValues } from './use-register-form' +import type { RegisterFormValues } from '../model/use-register-form' const RegisterForm = () => { const { control } = useFormContext() diff --git a/apps/web/views/auth/ui/register-page-view.tsx b/apps/web/views/auth/ui/register-page-view.tsx new file mode 100644 index 00000000..180f21ac --- /dev/null +++ b/apps/web/views/auth/ui/register-page-view.tsx @@ -0,0 +1,69 @@ +'use client' + +import Link from 'next/link' +import { useRouter } from 'next/navigation' + +import { Button, Form, toast } from '@repo/ui' + +import { useRegister } from '@/shared/api/use-auth' +import { ROUTES } from '@/shared/config' +import { isApiError } from '@/shared/lib/api/utils' + +import { useRegisterForm, type RegisterFormValues } from '../model/use-register-form' +import { AuthFormLayout } from './auth-form-layout' +import { RegisterForm } from './register-form' + +function RegisterPageView() { + const form = useRegisterForm() + + const registerMutation = useRegister() + const router = useRouter() + + const onSubmit = async (data: RegisterFormValues) => { + try { + await registerMutation.mutateAsync(data) + router.push(ROUTES.teams) + } catch (error) { + if (isApiError(error)) { + toast.error(error.message) + } else { + throw error + } + } + } + + return ( +
+ + + Зарегистрироваться + + } + > +
+ +

+ Уже есть аккаунт?{' '} + + Войти + +

+
+
+
+ + ) +} + +export { RegisterPageView } diff --git a/apps/web/views/home/model/content.ts b/apps/web/views/home/model/content.ts index cac770d5..feda8d2d 100644 --- a/apps/web/views/home/model/content.ts +++ b/apps/web/views/home/model/content.ts @@ -1,4 +1,3 @@ -import { ROUTES } from '@/shared/config/routes' import type { ComponentType, SVGProps } from 'react' import { @@ -14,6 +13,8 @@ import { Zap, } from '@repo/ui/icons' +import { ROUTES } from '@/shared/config' + type IconType = ComponentType> export const navigationItems = [ diff --git a/apps/web/views/home/ui/home-header.tsx b/apps/web/views/home/ui/home-header.tsx index 0dabc700..24164504 100644 --- a/apps/web/views/home/ui/home-header.tsx +++ b/apps/web/views/home/ui/home-header.tsx @@ -1,9 +1,10 @@ -import { ROUTES } from '@/shared/config/routes' import Link from 'next/link' import { Button } from '@repo/ui' import { Github, KanbanSquare } from '@repo/ui/icons' +import { ROUTES } from '@/shared/config' + import { navigationItems } from '../model/content' function HomeHeader() { diff --git a/apps/web/views/projects/ui/create-project-dialog.tsx b/apps/web/views/projects/ui/create-project-dialog.tsx index aebf46e8..72748bf9 100644 --- a/apps/web/views/projects/ui/create-project-dialog.tsx +++ b/apps/web/views/projects/ui/create-project-dialog.tsx @@ -1,11 +1,5 @@ 'use client' -import { - isValidProjectCode, - normalizeProjectCodeInput, - PROJECT_CODE_MAX_LENGTH, - PROJECT_CODE_MIN_LENGTH, -} from '@/lib/projects/project-code' import { useEffect, useState } from 'react' import { @@ -19,6 +13,13 @@ import { Label, } from '@repo/ui' +import { + isValidProjectCode, + normalizeProjectCodeInput, + PROJECT_CODE_MAX_LENGTH, + PROJECT_CODE_MIN_LENGTH, +} from '@/shared/lib/projects' + import { projectDialogContentClassName, projectDialogFooterClassName, diff --git a/apps/web/views/projects/ui/project-card.tsx b/apps/web/views/projects/ui/project-card.tsx index 7523909e..09cc9895 100644 --- a/apps/web/views/projects/ui/project-card.tsx +++ b/apps/web/views/projects/ui/project-card.tsx @@ -1,10 +1,10 @@ 'use client' -import type { ProjectCatalogItem } from '@/lib/projects/catalog' - import { cn } from '@repo/ui' import { ArrowRight, KanbanSquare, ListTodo } from '@repo/ui/icons' +import type { ProjectCatalogItem } from '@/shared/lib/projects' + interface Props { project: ProjectCatalogItem onOpen: (project: ProjectCatalogItem) => void diff --git a/apps/web/views/projects/ui/project-detail-page-view.tsx b/apps/web/views/projects/ui/project-detail-page-view.tsx index 56fe3f77..26d5a81b 100644 --- a/apps/web/views/projects/ui/project-detail-page-view.tsx +++ b/apps/web/views/projects/ui/project-detail-page-view.tsx @@ -1,8 +1,5 @@ 'use client' -import { useTeamDetail } from '@/hooks/api/use-teams' -import { formatProjectNameFromId, getProjectById } from '@/lib/projects/catalog' -import { teamRoutes } from '@/shared/config/routes' import Link from 'next/link' import { useParams } from 'next/navigation' @@ -16,6 +13,10 @@ import { SquareKanban, } from '@repo/ui/icons' +import { useTeamDetail } from '@/shared/api/use-teams' +import { teamRoutes } from '@/shared/config' +import { formatProjectNameFromId, getProjectById } from '@/shared/lib/projects' + import { projectPageSubtitleClassName, projectPageTitleClassName } from '../lib/styles' const actionCards = [ diff --git a/apps/web/views/projects/ui/projects-page-view.tsx b/apps/web/views/projects/ui/projects-page-view.tsx index 3ac10e88..fbc14187 100644 --- a/apps/web/views/projects/ui/projects-page-view.tsx +++ b/apps/web/views/projects/ui/projects-page-view.tsx @@ -1,18 +1,19 @@ 'use client' -import { useTeamDetail } from '@/hooks/api/use-teams' -import { - buildTeamProjectHref, - createProjectId, - projectCatalog, - type ProjectCatalogItem, -} from '@/lib/projects/catalog' import { useParams, useRouter } from 'next/navigation' import { useState } from 'react' import { Button, EmptyState, Input } from '@repo/ui' import { FolderKanban, Plus, Search } from '@repo/ui/icons' +import { useTeamDetail } from '@/shared/api/use-teams' +import { + buildTeamProjectHref, + createProjectId, + projectCatalog, + type ProjectCatalogItem, +} from '@/shared/lib/projects' + import { projectPageHeaderClassName, projectPagePrimaryButtonClassName, diff --git a/apps/web/views/teams/ui/create-team-dialog.tsx b/apps/web/views/teams/ui/create-team-dialog.tsx index 548128c8..fd901b9e 100644 --- a/apps/web/views/teams/ui/create-team-dialog.tsx +++ b/apps/web/views/teams/ui/create-team-dialog.tsx @@ -1,8 +1,5 @@ 'use client' -import { useCreateTeam } from '@/hooks/api/use-teams' -import { isApiError } from '@/lib/api/utils' -import { ROUTES } from '@/shared/config/routes' import { useRouter } from 'next/navigation' import { useState } from 'react' @@ -19,6 +16,10 @@ import { toast, } from '@repo/ui' +import { useCreateTeam } from '@/shared/api/use-teams' +import { ROUTES } from '@/shared/config' +import { isApiError } from '@/shared/lib/api/utils' + import { teamDialogContentClassName, teamDialogFooterClassName, diff --git a/apps/web/views/teams/ui/team-settings-page-view.tsx b/apps/web/views/teams/ui/team-settings-page-view.tsx index c60a23fd..eb1c7af6 100644 --- a/apps/web/views/teams/ui/team-settings-page-view.tsx +++ b/apps/web/views/teams/ui/team-settings-page-view.tsx @@ -1,6 +1,5 @@ 'use client' -import { useTeamDetail } from '@/hooks/api/use-teams' import { useParams } from 'next/navigation' import { useEffect, useState } from 'react' @@ -28,6 +27,8 @@ import { } from '@repo/ui' import { Crown, Mail, Settings2, Shield, Trash2, UserPlus, Users } from '@repo/ui/icons' +import { useTeamDetail } from '@/shared/api/use-teams' + import { teamDialogContentClassName, teamDialogFooterClassName, diff --git a/apps/web/views/teams/ui/teams-page-view.tsx b/apps/web/views/teams/ui/teams-page-view.tsx index 1a21c422..49b6881e 100644 --- a/apps/web/views/teams/ui/teams-page-view.tsx +++ b/apps/web/views/teams/ui/teams-page-view.tsx @@ -1,13 +1,14 @@ 'use client' -import { useTeamsList } from '@/hooks/api/use-teams' -import { ROUTES, teamRoutes } from '@/shared/config/routes' import { useRouter } from 'next/navigation' import { useMemo } from 'react' import { Button, EmptyState } from '@repo/ui' import { Plus, Users } from '@repo/ui/icons' +import { useTeamsList } from '@/shared/api/use-teams' +import { ROUTES, teamRoutes } from '@/shared/config' + import { mapTeamListItemToTeamCardModel } from '../lib/mappers' import { teamPageHeaderClassName, diff --git a/apps/web/widgets/main-layout/model/sidebar/navigation.ts b/apps/web/widgets/main-layout/model/sidebar/navigation.ts index 9c314d1b..a279c17d 100644 --- a/apps/web/widgets/main-layout/model/sidebar/navigation.ts +++ b/apps/web/widgets/main-layout/model/sidebar/navigation.ts @@ -1,7 +1,3 @@ -import { FEATURES } from '@/hooks/use-feature-flag' -import { projectCatalog } from '@/lib/projects/catalog' -import { ROUTES, SIDEBAR_ROUTE_IDS, teamRoutes } from '@/shared/config/routes' - import { Bell, FolderKanban, @@ -13,6 +9,9 @@ import { Users, } from '@repo/ui/icons' +import { FEATURES, ROUTES, SIDEBAR_ROUTE_IDS, teamRoutes } from '@/shared/config' +import { projectCatalog } from '@/shared/lib/projects' + import type { SidebarNavSection, SidebarProjectItem, diff --git a/apps/web/widgets/main-layout/model/sidebar/types.ts b/apps/web/widgets/main-layout/model/sidebar/types.ts index 9d842974..fd365861 100644 --- a/apps/web/widgets/main-layout/model/sidebar/types.ts +++ b/apps/web/widgets/main-layout/model/sidebar/types.ts @@ -1,7 +1,7 @@ -import type { SidebarRouteId } from '@/shared/config/routes' - import type { LucideIcon } from '@repo/ui/icons' +import type { SidebarRouteId } from '@/shared/config' + type SideBarStoreState = { isOpen: boolean } diff --git a/apps/web/widgets/main-layout/ui/header/profile-menu.tsx b/apps/web/widgets/main-layout/ui/header/profile-menu.tsx index e2bc0f2c..d8faaa31 100644 --- a/apps/web/widgets/main-layout/ui/header/profile-menu.tsx +++ b/apps/web/widgets/main-layout/ui/header/profile-menu.tsx @@ -1,8 +1,5 @@ 'use client' -import { useLogout } from '@/hooks/api/use-auth' -import { ROUTES } from '@/shared/config/routes' -import { useRouter } from 'next/navigation' import React from 'react' import { @@ -17,21 +14,26 @@ import { DropdownMenuTrigger, } from '@repo/ui' +import { useLogout, useMe } from '@/shared/api/use-auth' +import { ROUTE_QUERY_PARAMS, ROUTES } from '@/shared/config' + const currentUser = { name: 'Имя', avatar: 'AL', } const ProfileMenu = () => { - const router = useRouter() const logoutMutation = useLogout() - const handleLogout = async () => { - await logoutMutation.mutateAsync() - - router.push(ROUTES.login) + const handleLogout = () => { + logoutMutation.mutateAsync() + const url = new URL(ROUTES.login, window.location.origin) + url.searchParams.set(ROUTE_QUERY_PARAMS.clearAuth, '1') + window.location.assign(url) } + const profileQuery = useMe() + return ( @@ -48,7 +50,7 @@ const ProfileMenu = () => { {currentUser.avatar} - {currentUser.name} + {profileQuery.data?.name} diff --git a/apps/web/widgets/main-layout/ui/sidebar/sidebar.tsx b/apps/web/widgets/main-layout/ui/sidebar/sidebar.tsx index d6da24aa..26a478c5 100644 --- a/apps/web/widgets/main-layout/ui/sidebar/sidebar.tsx +++ b/apps/web/widgets/main-layout/ui/sidebar/sidebar.tsx @@ -1,9 +1,5 @@ 'use client' -import { ThemeToggle } from '@/features/theme' -import { useTeamsList } from '@/hooks/api/use-teams' -import { buildTeamProjectHref } from '@/lib/projects/catalog' -import { getSidebarRouteId, ROUTES, type SidebarRouteId } from '@/shared/config/routes' import Link from 'next/link' import { useParams, usePathname } from 'next/navigation' import React from 'react' @@ -11,6 +7,11 @@ import React from 'react' import { Avatar, AvatarFallback, cn } from '@repo/ui' import { KanbanSquare } from '@repo/ui/icons' +import { ThemeToggle } from '@/features/theme' +import { useTeamsList } from '@/shared/api/use-teams' +import { getSidebarRouteId, ROUTES, type SidebarRouteId } from '@/shared/config' +import { buildTeamProjectHref } from '@/shared/lib/projects' + import { getSidebarSections, sidebarCurrentUser,