add remove and add tariff modal windows
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "no-copy-admin-panel-frontend",
|
"name": "no-copy-admin-panel-frontend",
|
||||||
"version": "0.15.0",
|
"version": "0.16.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 2996",
|
"dev": "next dev -p 2996",
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ export async function updateTariffs(
|
|||||||
accountType: 'b2c' | 'b2b' | 'token'
|
accountType: 'b2c' | 'b2b' | 'token'
|
||||||
) {
|
) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
console.log(`updateTariffs - ${id}`);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/admin/control`, {
|
const response = await fetch(`${API_BASE_URL}/api/admin/control`, {
|
||||||
@@ -65,7 +64,7 @@ export async function updateTariffs(
|
|||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 40003,
|
msg_id: 40003,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'update',
|
action: 'add',
|
||||||
id: id,
|
id: id,
|
||||||
tariff_price: tariffPrice,
|
tariff_price: tariffPrice,
|
||||||
tariff_name: tariffName,
|
tariff_name: tariffName,
|
||||||
@@ -88,7 +87,104 @@ export async function updateTariffs(
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const parsed = await response.json();
|
const parsed = await response.json();
|
||||||
console.log(parsed);
|
|
||||||
|
if (parsed.message_code === 0) {
|
||||||
|
return parsed.message_body.message_body;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error(`${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addTariffs(
|
||||||
|
tariffPrice: number,
|
||||||
|
tariffName: string,
|
||||||
|
type: string,
|
||||||
|
tariffTokens: number,
|
||||||
|
maxFiles: number,
|
||||||
|
diskSize: number,
|
||||||
|
maxUsers: number,
|
||||||
|
description: string,
|
||||||
|
tariffTerm: 'MONTHLY' | 'YEAR',
|
||||||
|
accountType: 'b2c' | 'b2b' | 'token'
|
||||||
|
) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/admin/control`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
version: 1,
|
||||||
|
msg_id: 40003,
|
||||||
|
message_body: {
|
||||||
|
action: 'add',
|
||||||
|
tariff_price: tariffPrice,
|
||||||
|
tariff_name: tariffName,
|
||||||
|
type: type,
|
||||||
|
tariff_tokens: tariffTokens,
|
||||||
|
max_files: maxFiles,
|
||||||
|
disk_size: diskSize,
|
||||||
|
max_users: maxUsers,
|
||||||
|
description: description,
|
||||||
|
tariff_term: tariffTerm,
|
||||||
|
account_type: accountType
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const parsed = await response.json();
|
||||||
|
|
||||||
|
if (parsed.message_code === 0) {
|
||||||
|
return parsed.message_body.message_body;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error(`${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeTariffs(
|
||||||
|
id: number
|
||||||
|
) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/admin/control`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
version: 1,
|
||||||
|
msg_id: 40003,
|
||||||
|
message_body: {
|
||||||
|
action: 'remove',
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const parsed = await response.json();
|
||||||
|
|
||||||
if (parsed.message_code === 0) {
|
if (parsed.message_code === 0) {
|
||||||
return parsed.message_body.message_body;
|
return parsed.message_body.message_body;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@use './animation.scss';
|
@use './animation.scss';
|
||||||
@use './file-moderation-modal.scss';
|
@use './file-moderation-modal.scss';
|
||||||
@use './tariff-edit-modal.scss';
|
@use './tariff-edit-modal.scss';
|
||||||
|
@use './tariff-remove-modal.scss';
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--primary-color: #2563eb;
|
--primary-color: #2563eb;
|
||||||
@@ -11,8 +12,8 @@
|
|||||||
--secondary-hover: #4c5869;
|
--secondary-hover: #4c5869;
|
||||||
--success-color: #10b981;
|
--success-color: #10b981;
|
||||||
--success-hover: #0d8a60;
|
--success-hover: #0d8a60;
|
||||||
--danger-color: #ef4444;
|
--danger-color: #dc2626;
|
||||||
--danger-hover: #bd3434;
|
--danger-hover: #b91c1c;
|
||||||
--warning-color: #f59e0b;
|
--warning-color: #f59e0b;
|
||||||
--warning-hover: #b3750b;
|
--warning-hover: #b3750b;
|
||||||
--info-color: #3b82f6;
|
--info-color: #3b82f6;
|
||||||
@@ -297,6 +298,11 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
background: var(--danger-hover);
|
background: var(--danger-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
@@ -574,6 +580,8 @@
|
|||||||
border-top: 1px solid var(--border);
|
border-top: 1px solid var(--border);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-outline {
|
.btn-outline {
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
.tariff-delete-modal {
|
||||||
|
min-width: 400px;
|
||||||
|
max-width: 500px;
|
||||||
|
|
||||||
|
.tariff-delete-modal__title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tariff-delete-modal__warning {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #fef2f2;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-text {
|
||||||
|
margin: 0;
|
||||||
|
color: #991b1b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tariff-delete-modal__info {
|
||||||
|
padding: 12px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tariff-delete-modal__confirm {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #374151;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #dc2626;
|
||||||
|
ring: 2px solid #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tariff-delete-modal__actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import { addTariffs } from '@/app/actions/tariffActions';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
import DropDownList from '@/app/components/dropDownList';
|
||||||
|
|
||||||
|
interface NewTariff {
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
tokens: number;
|
||||||
|
maxFilesCount: number;
|
||||||
|
diskSize: number;
|
||||||
|
maxUsers: number;
|
||||||
|
description: string;
|
||||||
|
tariffTerm: 'MONTHLY' | 'YEAR';
|
||||||
|
accountType: 'b2c' | 'b2b' | 'token';
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TariffCreateModal({ onClose, onSuccess }: {
|
||||||
|
onClose: () => void;
|
||||||
|
onSuccess: () => void;
|
||||||
|
}) {
|
||||||
|
const [formData, setFormData] = useState<NewTariff>({
|
||||||
|
price: 0,
|
||||||
|
name: '',
|
||||||
|
tokens: 0,
|
||||||
|
maxFilesCount: 0,
|
||||||
|
diskSize: 0,
|
||||||
|
maxUsers: 0,
|
||||||
|
description: '',
|
||||||
|
tariffTerm: 'MONTHLY',
|
||||||
|
accountType: 'b2c',
|
||||||
|
type: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const [typeError, setTypeError] = useState('');
|
||||||
|
|
||||||
|
const createTariffMutation = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
return await addTariffs(
|
||||||
|
formData.price,
|
||||||
|
formData.name,
|
||||||
|
formData.type,
|
||||||
|
formData.tokens,
|
||||||
|
formData.maxFilesCount,
|
||||||
|
formData.diskSize,
|
||||||
|
formData.maxUsers,
|
||||||
|
formData.description,
|
||||||
|
formData.tariffTerm,
|
||||||
|
formData.accountType
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
if (data !== null && data !== undefined) {
|
||||||
|
toast.success('Тариф успешно создан');
|
||||||
|
onSuccess();
|
||||||
|
} else {
|
||||||
|
toast.error('Не удалось создать тариф');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
toast.error('Произошла ошибка при создании тарифа');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
if (!formData.type.trim()) {
|
||||||
|
setTypeError('Введите тип тарифа');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTypeError('');
|
||||||
|
createTariffMutation.mutate();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (field: string, value: any) => {
|
||||||
|
setFormData(prev => ({ ...prev, [field]: value }));
|
||||||
|
if (field === 'type') {
|
||||||
|
setTypeError('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tariff-edit-modal">
|
||||||
|
<h2 className="tariff-edit-modal__title">Создание нового тарифа</h2>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__content">
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Тип тарифа *</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className={`tariff-edit-modal__input ${typeError ? 'error' : ''}`}
|
||||||
|
value={formData.type}
|
||||||
|
onChange={(e) => handleChange('type', e.target.value)}
|
||||||
|
placeholder="Например: BASE, PREMIUM, TOKEN_1000"
|
||||||
|
/>
|
||||||
|
{typeError && <div className="error-message">{typeError}</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Название</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="tariff-edit-modal__input"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={(e) => handleChange('name', e.target.value)}
|
||||||
|
placeholder="Введите название тарифа"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Цена (₽)</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="tariff-edit-modal__input"
|
||||||
|
value={formData.price}
|
||||||
|
onChange={(e) => handleChange('price', Number(e.target.value))}
|
||||||
|
placeholder="Введите цену"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Количество токенов</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="tariff-edit-modal__input"
|
||||||
|
value={formData.tokens}
|
||||||
|
onChange={(e) => handleChange('tokens', Number(e.target.value))}
|
||||||
|
placeholder="Введите количество токенов"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Максимальное количество файлов</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="tariff-edit-modal__input"
|
||||||
|
value={formData.maxFilesCount}
|
||||||
|
onChange={(e) => handleChange('maxFilesCount', Number(e.target.value))}
|
||||||
|
placeholder="Введите максимальное количество файлов"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Размер диска (байт)</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="tariff-edit-modal__input"
|
||||||
|
value={formData.diskSize}
|
||||||
|
onChange={(e) => handleChange('diskSize', Number(e.target.value))}
|
||||||
|
placeholder="Введите размер диска в байтах"
|
||||||
|
min="0"
|
||||||
|
step="1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Максимальное количество пользователей</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="tariff-edit-modal__input"
|
||||||
|
value={formData.maxUsers}
|
||||||
|
onChange={(e) => handleChange('maxUsers', Number(e.target.value))}
|
||||||
|
placeholder="Введите максимальное количество пользователей"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Срок тарифа</label>
|
||||||
|
<DropDownList
|
||||||
|
value={formData.tariffTerm === 'YEAR' ? 'Год' : 'Месяц'}
|
||||||
|
callBack={(value: string) => {
|
||||||
|
handleChange('tariffTerm', value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<li value="MONTHLY">Месяц</li>
|
||||||
|
<li value="YEAR">Год</li>
|
||||||
|
</DropDownList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Тип аккаунта</label>
|
||||||
|
<DropDownList
|
||||||
|
value={
|
||||||
|
formData.accountType === 'b2c' ? 'B2C' :
|
||||||
|
formData.accountType === 'b2b' ? 'B2B' : 'Token'
|
||||||
|
}
|
||||||
|
callBack={(value: string) => {
|
||||||
|
handleChange('accountType', value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<li value="b2c">B2C</li>
|
||||||
|
<li value="b2b">B2B</li>
|
||||||
|
<li value="token">Token</li>
|
||||||
|
</DropDownList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__info-section">
|
||||||
|
<label className="tariff-edit-modal__label">Описание</label>
|
||||||
|
<textarea
|
||||||
|
className="tariff-edit-modal__textarea"
|
||||||
|
value={formData.description}
|
||||||
|
onChange={(e) => handleChange('description', e.target.value)}
|
||||||
|
placeholder="Введите описание тарифа"
|
||||||
|
rows={4}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-edit-modal__actions">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="btn btn-secondary"
|
||||||
|
disabled={createTariffMutation.isPending}
|
||||||
|
>
|
||||||
|
Отмена
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
className="btn btn-primary"
|
||||||
|
disabled={createTariffMutation.isPending}
|
||||||
|
>
|
||||||
|
{createTariffMutation.isPending ? 'Создание...' : 'Создать'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useMutation } from '@tanstack/react-query';
|
||||||
|
import { removeTariffs } from '@/app/actions/tariffActions';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
|
interface TariffDeleteModalProps {
|
||||||
|
tariffId: number;
|
||||||
|
tariffName: string;
|
||||||
|
onClose: () => void;
|
||||||
|
onSuccess: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TariffDeleteModal({ tariffId, tariffName, onClose, onSuccess }: TariffDeleteModalProps) {
|
||||||
|
const [isConfirmText, setIsConfirmText] = useState('');
|
||||||
|
const confirmText = 'УДАЛИТЬ';
|
||||||
|
|
||||||
|
const deleteTariffMutation = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
return await removeTariffs(tariffId);
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
if (data !== null && data !== undefined) {
|
||||||
|
toast.success('Тариф успешно удален');
|
||||||
|
onSuccess();
|
||||||
|
} else {
|
||||||
|
toast.error('Не удалось удалить тариф');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
toast.error('Произошла ошибка при удалении тарифа');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
deleteTariffMutation.mutate();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDisplayName = (name: string) => {
|
||||||
|
if (name) {
|
||||||
|
return name.toUpperCase().replace(/_/g, ' ');
|
||||||
|
}
|
||||||
|
return `ID: ${tariffId}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tariff-delete-modal">
|
||||||
|
<h2 className="tariff-delete-modal__title">Удаление тарифа</h2>
|
||||||
|
|
||||||
|
<div className="tariff-delete-modal__content">
|
||||||
|
<div className="tariff-delete-modal__warning">
|
||||||
|
<p className="warning-text">
|
||||||
|
Вы действительно хотите удалить тариф <strong>"{getDisplayName(tariffName)}"</strong>?
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-delete-modal__info">
|
||||||
|
<p>Это действие невозможно отменить.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-delete-modal__confirm">
|
||||||
|
<label className="confirm-label">
|
||||||
|
Для подтверждения введите <strong>{confirmText}</strong>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="confirm-input"
|
||||||
|
value={isConfirmText}
|
||||||
|
onChange={(e) => setIsConfirmText(e.target.value)}
|
||||||
|
placeholder={`Введите "${confirmText}"`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tariff-delete-modal__actions">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="btn btn-secondary"
|
||||||
|
disabled={deleteTariffMutation.isPending}
|
||||||
|
>
|
||||||
|
Отмена
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleDelete}
|
||||||
|
className="btn btn-danger"
|
||||||
|
disabled={isConfirmText !== confirmText || deleteTariffMutation.isPending}
|
||||||
|
>
|
||||||
|
{deleteTariffMutation.isPending ? 'Удаление...' : 'Удалить'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,12 +6,17 @@ import { convertBytes } from '@/app/lib/convertBytes';
|
|||||||
import { IconDoubleArrowRight, IconArrowRight, IconDoubleArrowLeft, IconArrowLeft } from '@/app/ui/icons/icons';
|
import { IconDoubleArrowRight, IconArrowRight, IconDoubleArrowLeft, IconArrowLeft } from '@/app/ui/icons/icons';
|
||||||
import ModalWindow from '@/app/components/modalWindow';
|
import ModalWindow from '@/app/components/modalWindow';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { EditingTariff, TariffEditModal } from './TariffEditModal'
|
import { EditingTariff, TariffEditModal } from './TariffEditModal';
|
||||||
|
import { TariffCreateModal } from './TariffCreateModal';
|
||||||
|
import { TariffDeleteModal } from './TariffDeleteModal';
|
||||||
|
|
||||||
export default function TariffManagment() {
|
export default function TariffManagment() {
|
||||||
const [currentPage, setCurrentPage] = useState(0);
|
const [currentPage, setCurrentPage] = useState(0);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||||
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||||
const [editingTariff, setEditingTariff] = useState<EditingTariff | null>(null);
|
const [editingTariff, setEditingTariff] = useState<EditingTariff | null>(null);
|
||||||
|
const [deletingTariff, setDeletingTariff] = useState<{ id: number; name: string } | null>(null);
|
||||||
|
|
||||||
const { data: tariffData, isLoading, isError, isFetching, error } = useTariffsData(currentPage);
|
const { data: tariffData, isLoading, isError, isFetching, error } = useTariffsData(currentPage);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -48,6 +53,14 @@ export default function TariffManagment() {
|
|||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteClick = (tariff: any) => {
|
||||||
|
setDeletingTariff({
|
||||||
|
id: tariff.id,
|
||||||
|
name: tariff.name || tariff.type
|
||||||
|
});
|
||||||
|
setIsDeleteModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
const formatPrice = (price: number) => {
|
const formatPrice = (price: number) => {
|
||||||
return new Intl.NumberFormat('ru-RU').format(price);
|
return new Intl.NumberFormat('ru-RU').format(price);
|
||||||
};
|
};
|
||||||
@@ -92,7 +105,10 @@ export default function TariffManagment() {
|
|||||||
<div className="content-header">
|
<div className="content-header">
|
||||||
<h3>Управление тарифными планами</h3>
|
<h3>Управление тарифными планами</h3>
|
||||||
<div className="content-header-actions">
|
<div className="content-header-actions">
|
||||||
<button className="btn btn-primary">
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={() => setIsCreateModalOpen(true)}
|
||||||
|
>
|
||||||
<span>➕</span>
|
<span>➕</span>
|
||||||
<span>Создать тариф</span>
|
<span>Создать тариф</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -124,6 +140,12 @@ export default function TariffManagment() {
|
|||||||
>
|
>
|
||||||
Редактировать
|
Редактировать
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-outline btn-sm btn-danger"
|
||||||
|
onClick={() => handleDeleteClick(tariff)}
|
||||||
|
>
|
||||||
|
Удалить
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -205,12 +227,7 @@ export default function TariffManagment() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isFetching && !isLoading && (
|
|
||||||
<div className="refetching-indicator">Обновление...</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Модальное окно редактирования тарифа */}
|
{/* Модальное окно редактирования тарифа */}
|
||||||
<ModalWindow state={isModalOpen} callBack={setIsModalOpen}>
|
<ModalWindow state={isModalOpen} callBack={setIsModalOpen}>
|
||||||
{editingTariff && (
|
{editingTariff && (
|
||||||
@@ -224,6 +241,31 @@ export default function TariffManagment() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</ModalWindow>
|
</ModalWindow>
|
||||||
|
{/* Модальное окно создания тарифа */}
|
||||||
|
<ModalWindow state={isCreateModalOpen} callBack={setIsCreateModalOpen}>
|
||||||
|
<TariffCreateModal
|
||||||
|
onClose={() => setIsCreateModalOpen(false)}
|
||||||
|
onSuccess={() => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['tariffsData'] });
|
||||||
|
setIsCreateModalOpen(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ModalWindow>
|
||||||
|
{/* Модальное окно удаления тарифа */}
|
||||||
|
<ModalWindow state={isDeleteModalOpen} callBack={setIsDeleteModalOpen}>
|
||||||
|
{deletingTariff && (
|
||||||
|
<TariffDeleteModal
|
||||||
|
tariffId={deletingTariff.id}
|
||||||
|
tariffName={deletingTariff.name}
|
||||||
|
onClose={() => setIsDeleteModalOpen(false)}
|
||||||
|
onSuccess={() => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['tariffsData'] });
|
||||||
|
setIsDeleteModalOpen(false);
|
||||||
|
setDeletingTariff(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ModalWindow>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user