feat: public admin avatar endpoint, real admin avatar in user chat
This commit is contained in:
@@ -30,6 +30,17 @@ export async function updateAdminUser(
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AdminAvatarResponse = {
|
||||||
|
avatar: string | null
|
||||||
|
avatarType: string | null
|
||||||
|
avatarStyle: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAdminAvatar(): Promise<AdminAvatarResponse> {
|
||||||
|
const { data } = await apiClient.get<AdminAvatarResponse>('admin/avatar')
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
export async function deleteAdminUser(id: string): Promise<void> {
|
export async function deleteAdminUser(id: string): Promise<void> {
|
||||||
await apiClient.delete(`admin/users/${id}`)
|
await apiClient.delete(`admin/users/${id}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import Box from '@mui/material/Box'
|
|||||||
import Button from '@mui/material/Button'
|
import Button from '@mui/material/Button'
|
||||||
import Stack from '@mui/material/Stack'
|
import Stack from '@mui/material/Stack'
|
||||||
import Typography from '@mui/material/Typography'
|
import Typography from '@mui/material/Typography'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { useUnit } from 'effector-react'
|
import { useUnit } from 'effector-react'
|
||||||
|
import { fetchAdminAvatar } from '@/entities/user/api/user-api'
|
||||||
import { $user } from '@/shared/model/auth'
|
import { $user } from '@/shared/model/auth'
|
||||||
import { ChatMessageBubble } from '@/shared/ui/ChatMessageBubble'
|
import { ChatMessageBubble } from '@/shared/ui/ChatMessageBubble'
|
||||||
import { OrderMessageBody } from '@/shared/ui/OrderMessageBody'
|
import { OrderMessageBody } from '@/shared/ui/OrderMessageBody'
|
||||||
@@ -29,6 +31,12 @@ export function OrderChat({ messages, isPending, onSend }: Props) {
|
|||||||
const canSend = text.replace(/<[^>]*>/g, ' ').trim().length > 0
|
const canSend = text.replace(/<[^>]*>/g, ' ').trim().length > 0
|
||||||
const currentUser = useUnit($user)
|
const currentUser = useUnit($user)
|
||||||
|
|
||||||
|
const adminAvatarQuery = useQuery({
|
||||||
|
queryKey: ['admin', 'avatar'],
|
||||||
|
queryFn: fetchAdminAvatar,
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
})
|
||||||
|
|
||||||
const handleSend = () => {
|
const handleSend = () => {
|
||||||
if (!canSend || isPending) return
|
if (!canSend || isPending) return
|
||||||
onSend(text.trim())
|
onSend(text.trim())
|
||||||
@@ -43,8 +51,15 @@ export function OrderChat({ messages, isPending, onSend }: Props) {
|
|||||||
<Stack spacing={1} sx={{ mb: 2 }}>
|
<Stack spacing={1} sx={{ mb: 2 }}>
|
||||||
{messages.map((m) => {
|
{messages.map((m) => {
|
||||||
const isAdminMsg = m.authorType === 'admin'
|
const isAdminMsg = m.authorType === 'admin'
|
||||||
|
const adminAv = adminAvatarQuery.data
|
||||||
const avatarNode = isAdminMsg ? (
|
const avatarNode = isAdminMsg ? (
|
||||||
<UserAvatar userId="admin" avatarUrl={null} avatarType={null} avatarStyle={null} size={24} />
|
<UserAvatar
|
||||||
|
userId="admin"
|
||||||
|
avatarUrl={adminAv?.avatar}
|
||||||
|
avatarType={adminAv?.avatarType}
|
||||||
|
avatarStyle={adminAv?.avatarStyle}
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
) : currentUser ? (
|
) : currentUser ? (
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
userId={currentUser.id}
|
userId={currentUser.id}
|
||||||
|
|||||||
Binary file not shown.
@@ -1,3 +1,4 @@
|
|||||||
|
import { normalizeEmail } from '../../lib/auth.js'
|
||||||
import { prisma } from '../../lib/prisma.js'
|
import { prisma } from '../../lib/prisma.js'
|
||||||
|
|
||||||
export async function registerAdminProfileRoutes(fastify) {
|
export async function registerAdminProfileRoutes(fastify) {
|
||||||
@@ -15,6 +16,20 @@ export async function registerAdminProfileRoutes(fastify) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fastify.get('/api/admin/avatar', async (request, reply) => {
|
||||||
|
const adminEmail = normalizeEmail(process.env.ADMIN_EMAIL)
|
||||||
|
if (!adminEmail || !adminEmail.includes('@')) return reply.code(404).send({ error: 'Администратор не найден' })
|
||||||
|
|
||||||
|
const user = await prisma.user.findUnique({ where: { email: adminEmail } })
|
||||||
|
if (!user) return reply.code(404).send({ error: 'Администратор не найден' })
|
||||||
|
|
||||||
|
return {
|
||||||
|
avatar: user.avatar,
|
||||||
|
avatarType: user.avatarType,
|
||||||
|
avatarStyle: user.avatarStyle,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
fastify.patch('/api/admin/profile', { preHandler: [fastify.verifyAdmin] }, async (request, reply) => {
|
fastify.patch('/api/admin/profile', { preHandler: [fastify.verifyAdmin] }, async (request, reply) => {
|
||||||
const userId = request.user.sub
|
const userId = request.user.sub
|
||||||
const nameRaw = request.body?.displayName
|
const nameRaw = request.body?.displayName
|
||||||
|
|||||||
Reference in New Issue
Block a user