refactor(web): align account preference requests with API contracts (#41748)

This commit is contained in:
非法操作 2026-09-03 12:55:44 +00:00 committed by GitHub
parent 24f9f07752
commit 8c98e3fad5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 25 additions and 41 deletions

View File

@ -70,7 +70,14 @@ describe('MailAndPasswordAuth', () => {
await user.type(passwordInput, 'strong-password{Enter}')
await waitFor(() => {
expect(webAppLoginMock).toHaveBeenCalledTimes(1)
expect(webAppLoginMock).toHaveBeenCalledWith({
url: '/login',
body: {
email: 'user@example.com',
password: expect.any(String),
remember_me: true,
},
})
})
})

View File

@ -10,7 +10,6 @@ import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { resolveWebAppLoginRedirect } from '@/app/(shareLayout)/webapp-signin/login-redirect'
import { emailRegex } from '@/config'
import { useLocale } from '@/context/i18n'
import { useWebAppStore } from '@/context/web-app-context'
import Link from '@/next/link'
import { useRouter, useSearchParams } from '@/next/navigation'
@ -28,7 +27,6 @@ type MailAndPasswordAuthProps = {
export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAuthProps) {
const { t } = useTranslation()
const locale = useLocale()
const router = useRouter()
const searchParams = useSearchParams()
const [showPassword, setShowPassword] = useState(false)
@ -69,7 +67,6 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
const loginData = {
email,
password: encryptPassword(password),
language: locale,
remember_me: true,
}

View File

@ -4,7 +4,6 @@ import { QueryClientProvider } from '@tanstack/react-query'
import { screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { languages } from '@/i18n-config/language'
import { updateUserProfile } from '@/service/common'
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
import { render } from '@/test/console/render'
import { timezones } from '@/utils/timezone'
@ -30,16 +29,10 @@ vi.mock('@/context/i18n', () => ({
useLocale: () => mockLocale,
}))
vi.mock('@/service/common', () => ({
updateUserProfile: vi.fn(),
}))
vi.mock('@/i18n-config', () => ({
setLocaleOnClient: vi.fn(),
}))
const updateUserProfileMock = vi.mocked(updateUserProfile)
const createUserProfile = (
overrides: Partial<GetAccountProfileResponse> = {},
): GetAccountProfileResponse => ({
@ -149,7 +142,6 @@ describe('PreferencePage - Interactions', () => {
it('should show success toast when language updates', async () => {
const chinese = getLanguageOption('zh-Hans')
mockUserProfile = createUserProfile({ interface_language: 'en-US' })
updateUserProfileMock.mockResolvedValueOnce({ result: 'success' })
renderPage()
@ -157,16 +149,17 @@ describe('PreferencePage - Interactions', () => {
expect(await screen.findByText('common.actionMsg.modifiedSuccessfully')).toBeInTheDocument()
await waitFor(() => {
expect(updateUserProfileMock).toHaveBeenCalledWith({
url: '/account/interface-language',
body: { interface_language: chinese.value },
})
expect(mockRequest).toHaveBeenCalled()
})
expect(mockRequest.mock.calls[0]?.[0]).toEqual(expect.stringContaining('/account/profile'))
const request = mockRequest.mock.calls[0]?.[2]?.request as Request
expect(request.method).toBe('PATCH')
await expect(request.json()).resolves.toEqual({ interface_language: chinese.value })
})
it('should show error toast when language update fails', async () => {
const chinese = getLanguageOption('zh-Hans')
updateUserProfileMock.mockRejectedValueOnce(new Error('Update failed'))
mockRequest.mockRejectedValueOnce(new Error('Update failed'))
renderPage()
@ -186,9 +179,9 @@ describe('PreferencePage - Interactions', () => {
await waitFor(() => {
expect(mockRequest).toHaveBeenCalled()
})
expect(mockRequest.mock.calls[0]?.[0]).toEqual(expect.stringContaining('/account/timezone'))
expect(mockRequest.mock.calls[0]?.[0]).toEqual(expect.stringContaining('/account/profile'))
const request = mockRequest.mock.calls[0]?.[2]?.request as Request
expect(request.method).toBe('POST')
expect(request.method).toBe('PATCH')
await expect(request.json()).resolves.toEqual({ timezone: midwayTimezone.value })
}, 15000)

View File

@ -19,7 +19,6 @@ import { setLocaleOnClient } from '@/i18n-config'
import { languages } from '@/i18n-config/language'
import { useRouter } from '@/next/navigation'
import { consoleQuery } from '@/service/client'
import { updateUserProfile } from '@/service/common'
import { timezones } from '@/utils/timezone'
type SelectOption = {
@ -48,7 +47,7 @@ export default function PreferencePage() {
...userProfileQueryOptions(),
select: (data) => data.profile,
})
const updateTimezone = useMutation(consoleQuery.account.timezone.post.mutationOptions())
const updateProfile = useMutation(consoleQuery.account.profile.patch.mutationOptions())
const [editing, setEditing] = useState(false)
const { t } = useTranslation()
const router = useRouter()
@ -68,11 +67,9 @@ export default function PreferencePage() {
if (isThemeOption(item.value)) setTheme(item.value)
}
const handleSelectLanguage = async (item: SelectOption) => {
const url = '/account/interface-language'
const bodyKey = 'interface_language'
setEditing(true)
try {
await updateUserProfile({ url, body: { [bodyKey]: item.value } })
await updateProfile.mutateAsync({ body: { interface_language: item.value } })
toast.success(t(($) => $['actionMsg.modifiedSuccessfully'], { ns: 'common' }))
setLocaleOnClient(item.value.toString() as Locale, false)
router.refresh()
@ -85,7 +82,7 @@ export default function PreferencePage() {
const handleSelectTimezone = async (item: TimezoneOption) => {
setEditing(true)
try {
await updateTimezone.mutateAsync({ body: { timezone: item.value } })
await updateProfile.mutateAsync({ body: { timezone: item.value } })
toast.success(t(($) => $['actionMsg.modifiedSuccessfully'], { ns: 'common' }))
} catch (e) {
toast.error((e as Error).message)

View File

@ -1,3 +1,4 @@
import type { LoginPayload } from '@dify/contracts/api/console/login/types.gen'
import { Button } from '@langgenius/dify-ui/button'
import { Field, FieldError, FieldLabel } from '@langgenius/dify-ui/field'
import { Form } from '@langgenius/dify-ui/form'
@ -10,7 +11,6 @@ import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { trackEvent } from '@/app/components/base/amplitude'
import { emailRegex } from '@/config'
import { useLocale } from '@/context/i18n'
import Link from '@/next/link'
import { useRouter, useSearchParams } from '@/next/navigation'
import { consoleQuery } from '@/service/client'
@ -26,21 +26,12 @@ type MailAndPasswordAuthProps = {
isEmailSetup: boolean
}
type LoginRequestBody = {
email: string
password: string
language: string
remember_me: boolean
invite_token?: string
}
function hasErrorCode(error: unknown, code: string) {
return typeof error === 'object' && error !== null && 'code' in error && error.code === code
}
export default function MailAndPasswordAuth({ isInvite, isEmailSetup }: MailAndPasswordAuthProps) {
const { t } = useTranslation()
const locale = useLocale()
const router = useRouter()
const queryClient = useQueryClient()
const searchParams = useSearchParams()
@ -54,10 +45,9 @@ export default function MailAndPasswordAuth({ isInvite, isEmailSetup }: MailAndP
if (isLoading) return
try {
setIsLoading(true)
const loginData: LoginRequestBody = {
const loginData: LoginPayload = {
email,
password: encryptPassword(password),
language: locale,
remember_me: true,
}
if (isInvite)

View File

@ -636,12 +636,12 @@ describe('consoleQuery education defaults', () => {
})
describe('consoleQuery account profile mutation defaults', () => {
it('should invalidate the account profile after a timezone update', async () => {
it('should invalidate the account profile after a profile update', async () => {
const consoleQuery = await loadConsoleQuery()
const queryClient = new QueryClient()
const invalidateQueries = vi.spyOn(queryClient, 'invalidateQueries')
await consoleQuery.account.timezone.post.mutationOptions().onSuccess?.(
await consoleQuery.account.profile.patch.mutationOptions().onSuccess?.(
{
id: 'user-1',
name: 'Test User',

View File

@ -459,8 +459,8 @@ export const consoleQuery: RouterUtils<typeof consoleClient> = createTanstackQue
},
},
},
timezone: {
post: {
profile: {
patch: {
mutationOptions: {
onSuccess: async (_data, _variables, _onMutateResult, context) => {
await context.client.invalidateQueries({