@@ -1,7 +1,7 @@ import React, { useState } from 'react' import { Box, TextField, Typography } from '@mui/material' import axios from 'axios' -import { Dayjs } from 'dayjs' +import dayjs, { Dayjs } from 'dayjs' import { useRouter } from 'next/navigation' import { useSession } from 'next-auth/react' @@ -37,16 +37,34 @@ export const ApiKeyModal = ({ return } - const keyName = `Ключ ${Math.floor(Math.random() * 100000) + 1}` + const trimmedTitle = title.trim() + + if (!trimmedTitle) { + showMessage('Введите название ключа') + return + } + + if (endDate && endDate !== '') { + const dateStr = + typeof endDate === 'string' ? endDate : (endDate as Dayjs).format('YYYY-MM-DD') + + const selectedDate = dayjs(dateStr, 'YYYY-MM-DD').startOf('day') + const today = dayjs().startOf('day') + + if (selectedDate.isBefore(today)) { + showMessage('Дата действия ключа не может быть в прошлом') + return + } + } setIsLoading(true) const response = endDate && endDate !== '' ? await accountApi.createApiKeys( - { name: title !== '' ? title : keyName, expires_at: endDate }, + { name: trimmedTitle, expires_at: endDate }, data?.access ) - : await accountApi.createApiKeys({ name: title !== '' ? title : keyName }, data?.access) + : await accountApi.createApiKeys({ name: trimmedTitle }, data?.access) if (response.status >= 400 && response.data?.detail) { showMessage(response.data.detail) @@ -1,4 +1,4 @@ -import axios, { AxiosResponse } from 'axios' +import axios from 'axios' import { API_URL } from '#/shared/lib/constants' @@ -10,7 +10,7 @@ export const changeAccess = async ( ): Promise => { if (!value) { try { - const { data } = await axios.put<{ models: string }, AxiosResponse>( + const { data, status } = await axios.put( API_URL + '/auth/business-host/allowed-models', { models: [title], @@ -19,9 +19,15 @@ export const changeAccess = async ( headers: { Authorization: `Bearer ${token}`, }, + validateStatus: (s) => s < 500, } ) - return data + + if (status >= 400) { + return [] + } + + return Array.isArray(data) ? data : [] } catch (err) { return [] } @@ -29,7 +35,7 @@ export const changeAccess = async ( if (value) { try { - const { data } = await axios.delete<{ models: string }, AxiosResponse>( + const { data, status } = await axios.delete( API_URL + '/auth/business-host/allowed-models', { headers: { @@ -38,9 +44,15 @@ export const changeAccess = async ( data: { models: [title], }, + validateStatus: (s) => s < 500, } ) - return data + + if (status >= 400) { + return [] + } + + return Array.isArray(data) ? data : [] } catch (err) { return [] } @@ -1,6 +1,7 @@ import React from 'react' import { SwitchCustom } from '#/shared' +import { useShowDataStore } from '#/shared/lib/hooks/use-show-data' import { changeAccess } from '../api/change-access' import { AllowedModels } from '../api/types' @@ -9,11 +10,18 @@ type SwitchAccess = { title: string token?: string updateAccessModels: (models: AllowedModels[]) => void + isOwner?: boolean } -export const SwitchAccess: React.FC = ({ isAllowed, title, token, updateAccessModels }) => { +export const SwitchAccess: React.FC = ({ isAllowed, title, token, updateAccessModels, isOwner = true }) => { + const { showMessage } = useShowDataStore() + const change = () => { + if (!isOwner) { + showMessage('У вас недостаточно прав для изменения доступа') + return + } changeAccess(token, isAllowed, title).then((res) => { - if (res.length === 0) { + if (!Array.isArray(res) || res.length === 0) { return } updateAccessModels(res) @@ -20,7 +20,8 @@ export const ModalImage = ({ file, ...image }: ModalImageProps) => { onLoadingComplete={() => { updateImageState(true) }} - loading='lazy' + loading='eager' + priority src={file} width={'1500'} height={'1500'} @@ -33,6 +34,7 @@ export const ModalImage = ({ file, ...image }: ModalImageProps) => { onLoad={() => updateImageState(true)} alt='К сожалению, изображение не загрузилось' className={styles.image_style} + loading='eager' /> )} @@ -60,12 +60,15 @@ export default function FullScreenModal({ modal, setModal, image }: IProps) { height={'1500'} alt='К сожалению, изображение не загрузилось' className={styles.image_style} + loading='eager' + priority /> ) : ( К сожалению, изображение не загрузилось )} @@ -32,14 +32,14 @@ export const InviteModal: FC = ({ open, onClose, showNewPerson const { handleSubmit, register, reset, setValue, getValues } = useForm() const [isLoading, setIsLoading] = useState(false) const [businessGroups, setBusinessGroups] = useState() - const [currentGroup, setCurrentGroup] = useState('') + const [currentGroupUid, setCurrentGroupUid] = useState('') const { showMessage } = useShowDataStore() const { data: session } = useSession() const onSubmit = async (data: any) => { setIsLoading(true) - const group: string | undefined = businessGroups?.find((el) => (el.title === currentGroup ? el.uid : ''))?.uid || "" + const group = currentGroupUid || '' const res = await invitePerson(role, data.limit, data.email, group, session?.access) if (res && res.data.detail && res.status >= 300) { @@ -55,9 +55,8 @@ export const InviteModal: FC = ({ open, onClose, showNewPerson setIsLoading(false) onClose() - + setCurrentGroupUid('') reset() - showNewPersons(res.data) } const checkError: SubmitErrorHandler = (data) => { @@ -87,16 +86,15 @@ export const InviteModal: FC = ({ open, onClose, showNewPerson Выберите роль - {/* Поле с выбором группы */} + {/* Поле с выбором группы — передаём объекты с uid, чтобы избежать дубликатов ключей при одинаковых названиях */} Выберите бизнес-группу + list={[{ uid: '', title: 'Без группы' }, ...(businessGroups ?? [])].reverse()} + valueKey="uid" + labelKey="title" + onChange={(e) => setCurrentGroupUid(e.target.value)} + value={currentGroupUid} + /> Укажите адрес электронной почты = ({ )}