fix: CI workflow, password reset flow, health/limits in services, session refactor, dead mixin stub cleanup
This commit is contained in:
parent
45dd592c40
commit
f4e15b45c9
95 changed files with 899 additions and 185 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router'
|
||||
import { SessionProvider } from '@features/auth/session'
|
||||
import { SessionProvider } from '@features/auth/session/session'
|
||||
import { ActiveThemeProvider } from '@features/themes/useActiveTheme'
|
||||
import { routes } from './routes'
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useCallback, useRef, useState, type DragEvent } from 'react'
|
|||
import { useTranslation } from '@shared/i18n/react'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { Button } from '@shared/ui/Button'
|
||||
import { useSession } from '@features/auth/session'
|
||||
import { useSession } from '@features/auth/session/useSession'
|
||||
import { AvatarUpload } from './avatar/AvatarUpload'
|
||||
|
||||
/** The mod's profile panel: big avatar with an accent ring, nick, email and join date. The avatar circle doubles as a file drop target. */
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|||
import { useCallback, useEffect, useId, useState, type ChangeEvent } from 'react'
|
||||
import { useTranslation } from '@shared/i18n/react'
|
||||
import { Notice } from '@shared/ui/Notice'
|
||||
import { useSession } from '@features/auth/session'
|
||||
import { useSession } from '@features/auth/session/useSession'
|
||||
import {
|
||||
addAvatarHistory,
|
||||
checkAvatarFile,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useTranslation } from '@shared/i18n/react'
|
||||
import { Navigate, Outlet, useLocation } from 'react-router'
|
||||
import { useSession } from './session'
|
||||
import { useSession } from './session/useSession'
|
||||
|
||||
export function RequireAuth() {
|
||||
const { t } = useTranslation('auth')
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { describeError } from '@shared/api/errors'
|
|||
import { Button } from '@shared/ui/Button'
|
||||
import { Notice } from '@shared/ui/Notice'
|
||||
import { TextField } from '@shared/ui/text-field/TextField'
|
||||
import { useSession } from '../session'
|
||||
import { useSession } from '../session/useSession'
|
||||
|
||||
export function LoginForm() {
|
||||
const { t } = useTranslation('auth')
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { describeError } from '@shared/api/errors'
|
|||
import { Button } from '@shared/ui/Button'
|
||||
import { Notice } from '@shared/ui/Notice'
|
||||
import { TextField } from '@shared/ui/text-field/TextField'
|
||||
import { useSession } from '../session'
|
||||
import { useSession } from '../session/useSession'
|
||||
import { validateEmail, validateNick, validatePassword } from '../validation'
|
||||
|
||||
export function RegisterForm() {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,10 @@
|
|||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { createContext, useCallback, useContext, useMemo, type ReactNode } from 'react'
|
||||
import { useCallback, useMemo, type ReactNode } from 'react'
|
||||
import { api } from '@shared/api/client'
|
||||
import type { Me } from '@shared/types'
|
||||
import { fetchMe, login, logout, register } from './api'
|
||||
import { fetchMe, login, logout, register } from '../api'
|
||||
import { SessionContext, type Session } from './sessionContext'
|
||||
import { hasSessionHint, setSessionHint } from './sessionHint'
|
||||
|
||||
type Session = {
|
||||
status: 'loading' | 'anonymous' | 'authenticated'
|
||||
me: Me | null
|
||||
signIn(email: string, password: string): Promise<void>
|
||||
signUp(email: string, password: string, nick: string): Promise<void>
|
||||
signOut(): Promise<void>
|
||||
}
|
||||
|
||||
const SessionContext = createContext<Session | null>(null)
|
||||
|
||||
export function SessionProvider({ children }: { children: ReactNode }) {
|
||||
const client = useQueryClient()
|
||||
// Restores the session after a reload: the refresh cookie survives, the
|
||||
|
|
@ -64,9 +54,3 @@ export function SessionProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
return <SessionContext value={value}>{children}</SessionContext>
|
||||
}
|
||||
|
||||
export function useSession(): Session {
|
||||
const session = useContext(SessionContext)
|
||||
if (!session) throw new Error('useSession outside SessionProvider')
|
||||
return session
|
||||
}
|
||||
12
frontend/src/features/auth/session/sessionContext.ts
Normal file
12
frontend/src/features/auth/session/sessionContext.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { createContext } from 'react'
|
||||
import type { Me } from '@shared/types'
|
||||
|
||||
export type Session = {
|
||||
status: 'loading' | 'anonymous' | 'authenticated'
|
||||
me: Me | null
|
||||
signIn(email: string, password: string): Promise<void>
|
||||
signUp(email: string, password: string, nick: string): Promise<void>
|
||||
signOut(): Promise<void>
|
||||
}
|
||||
|
||||
export const SessionContext = createContext<Session | null>(null)
|
||||
8
frontend/src/features/auth/session/useSession.ts
Normal file
8
frontend/src/features/auth/session/useSession.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { useContext } from 'react'
|
||||
import { SessionContext, type Session } from './sessionContext'
|
||||
|
||||
export function useSession(): Session {
|
||||
const session = useContext(SessionContext)
|
||||
if (!session) throw new Error('useSession outside SessionProvider')
|
||||
return session
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { screen } from '@testing-library/react'
|
||||
import { expect, test } from 'vitest'
|
||||
import { RequireAuth } from '../RequireAuth'
|
||||
import { useSession } from '../session'
|
||||
import { useSession } from '../session/useSession'
|
||||
import { renderApp } from '@test/render'
|
||||
import { json, mockFetch } from '@test/fetch'
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
|
|||
import { useTranslation } from '@shared/i18n/react'
|
||||
import { prefersReducedMotion } from '@shared/motion/reducedMotion'
|
||||
import { ButtonLink } from '@shared/ui/Button'
|
||||
import { useSession } from '../auth/session'
|
||||
import { useSession } from '../auth/session/useSession'
|
||||
import { useInView } from './effects/useInView'
|
||||
import '@features/landing/styles/sections.css'
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { Hero } from '../sections/hero/Hero'
|
|||
import { createMemoryRouter, RouterProvider } from 'react-router'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { initI18n } from '@app/i18n'
|
||||
import { SessionProvider } from '@features/auth/session'
|
||||
import { SessionProvider } from '@features/auth/session/session'
|
||||
import { json, mockFetch } from '@test/fetch'
|
||||
|
||||
test('reduced motion shows the full command at once', async () => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useTranslation } from '@shared/i18n/react'
|
|||
import { Link, useLocation } from 'react-router'
|
||||
import { Notice } from '@shared/ui/Notice'
|
||||
import { ApiError } from '@shared/api/client'
|
||||
import { useSession } from '@features/auth/session'
|
||||
import { useSession } from '@features/auth/session/useSession'
|
||||
import { listSlots } from '@features/configs/api'
|
||||
import { copyToSlot } from '../api'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useTranslation } from '@shared/i18n/react'
|
||||
import { Link } from 'react-router'
|
||||
import { useSession } from '@features/auth/session'
|
||||
import { useSession } from '@features/auth/session/useSession'
|
||||
import type { Me } from '../../types'
|
||||
|
||||
/** The pixel-heart mark, standalone (no badge background) — same shape as public/favicon.svg. */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render } from '@testing-library/react'
|
||||
import { createMemoryRouter, RouterProvider, type RouteObject } from 'react-router'
|
||||
import { SessionProvider } from '@features/auth/session'
|
||||
import { SessionProvider } from '@features/auth/session/session'
|
||||
|
||||
export function renderApp(routes: RouteObject[], initialPath = '/') {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue