From c74ef84d3760b8738ae5c98cf66d9157c504b99f Mon Sep 17 00:00:00 2001 From: smanylov Date: Mon, 1 Jun 2026 12:14:27 +0700 Subject: [PATCH] add remove and add tariff modal windows --- package.json | 2 +- src/app/actions/tariffActions.ts | 102 +++++++- src/app/styles/global-styles.scss | 12 +- src/app/styles/tariff-remove-modal.scss | 68 +++++ .../tariff-management/TariffCreateModal.tsx | 232 ++++++++++++++++++ .../tariff-management/TariffDeleteModal.tsx | 92 +++++++ .../tariff-management/tariff-management.tsx | 56 ++++- 7 files changed, 551 insertions(+), 13 deletions(-) create mode 100644 src/app/styles/tariff-remove-modal.scss create mode 100644 src/app/ui/tariff-management/TariffCreateModal.tsx create mode 100644 src/app/ui/tariff-management/TariffDeleteModal.tsx diff --git a/package.json b/package.json index bdf14c4..fd22a55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "no-copy-admin-panel-frontend", - "version": "0.15.0", + "version": "0.16.0", "private": true, "scripts": { "dev": "next dev -p 2996", diff --git a/src/app/actions/tariffActions.ts b/src/app/actions/tariffActions.ts index 9d0cc16..025bb32 100644 --- a/src/app/actions/tariffActions.ts +++ b/src/app/actions/tariffActions.ts @@ -56,7 +56,6 @@ export async function updateTariffs( accountType: 'b2c' | 'b2b' | 'token' ) { const token = await getSessionData('token'); - console.log(`updateTariffs - ${id}`); try { const response = await fetch(`${API_BASE_URL}/api/admin/control`, { @@ -65,7 +64,7 @@ export async function updateTariffs( version: 1, msg_id: 40003, message_body: { - action: 'update', + action: 'add', id: id, tariff_price: tariffPrice, tariff_name: tariffName, @@ -88,7 +87,104 @@ export async function updateTariffs( if (response.ok) { 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) { return parsed.message_body.message_body; diff --git a/src/app/styles/global-styles.scss b/src/app/styles/global-styles.scss index c651a87..611fa36 100644 --- a/src/app/styles/global-styles.scss +++ b/src/app/styles/global-styles.scss @@ -3,6 +3,7 @@ @use './animation.scss'; @use './file-moderation-modal.scss'; @use './tariff-edit-modal.scss'; +@use './tariff-remove-modal.scss'; :root { --primary-color: #2563eb; @@ -11,8 +12,8 @@ --secondary-hover: #4c5869; --success-color: #10b981; --success-hover: #0d8a60; - --danger-color: #ef4444; - --danger-hover: #bd3434; + --danger-color: #dc2626; + --danger-hover: #b91c1c; --warning-color: #f59e0b; --warning-hover: #b3750b; --info-color: #3b82f6; @@ -297,6 +298,11 @@ &:hover { background: var(--danger-hover); } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } } .btn { @@ -574,6 +580,8 @@ border-top: 1px solid var(--border); font-size: 12px; color: var(--text-secondary); + display: flex; + gap: 10px; } .btn-outline { diff --git a/src/app/styles/tariff-remove-modal.scss b/src/app/styles/tariff-remove-modal.scss new file mode 100644 index 0000000..d129438 --- /dev/null +++ b/src/app/styles/tariff-remove-modal.scss @@ -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; + } +} \ No newline at end of file diff --git a/src/app/ui/tariff-management/TariffCreateModal.tsx b/src/app/ui/tariff-management/TariffCreateModal.tsx new file mode 100644 index 0000000..5d693d7 --- /dev/null +++ b/src/app/ui/tariff-management/TariffCreateModal.tsx @@ -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({ + 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 ( +
+

Создание нового тарифа

+ +
+
+ + handleChange('type', e.target.value)} + placeholder="Например: BASE, PREMIUM, TOKEN_1000" + /> + {typeError &&
{typeError}
} +
+ +
+ + handleChange('name', e.target.value)} + placeholder="Введите название тарифа" + /> +
+ +
+ + handleChange('price', Number(e.target.value))} + placeholder="Введите цену" + min="0" + /> +
+ +
+ + handleChange('tokens', Number(e.target.value))} + placeholder="Введите количество токенов" + min="0" + /> +
+ +
+ + handleChange('maxFilesCount', Number(e.target.value))} + placeholder="Введите максимальное количество файлов" + min="0" + /> +
+ +
+ + handleChange('diskSize', Number(e.target.value))} + placeholder="Введите размер диска в байтах" + min="0" + step="1" + /> +
+ +
+ + handleChange('maxUsers', Number(e.target.value))} + placeholder="Введите максимальное количество пользователей" + min="0" + /> +
+ +
+ + { + handleChange('tariffTerm', value); + }} + > +
  • Месяц
  • +
  • Год
  • +
    +
    + +
    + + { + handleChange('accountType', value); + }} + > +
  • B2C
  • +
  • B2B
  • +
  • Token
  • +
    +
    + +
    + +