admin page
This commit is contained in:
@@ -12,7 +12,6 @@ interface FormState {
|
||||
contact_person: string
|
||||
contact_phone: string
|
||||
status: string
|
||||
bank_details: string
|
||||
}
|
||||
|
||||
function toForm(org: Organization): FormState {
|
||||
@@ -26,7 +25,6 @@ function toForm(org: Organization): FormState {
|
||||
contact_person: org.contact_person ?? '',
|
||||
contact_phone: org.contact_phone ?? '',
|
||||
status: org.status ?? '',
|
||||
bank_details: org.bank_details ? JSON.stringify(org.bank_details, null, 2) : '',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +45,9 @@ export function useOrganizationForm(
|
||||
const [form, setForm] = useState<FormState>(() =>
|
||||
org ? toForm(org) : {
|
||||
name: '', short_name: '', ogrn: '', kpp: '', legal_address: '',
|
||||
actual_address: '', contact_person: '', contact_phone: '', status: '', bank_details: '',
|
||||
actual_address: '', contact_person: '', contact_phone: '', status: '',
|
||||
},
|
||||
)
|
||||
const [bankError, setBankError] = useState<string | null>(null)
|
||||
const mutation = useUpdateOrganization(id)
|
||||
|
||||
// Sync local form state once the organization loads / changes.
|
||||
@@ -63,20 +60,9 @@ export function useOrganizationForm(
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setBankError(null)
|
||||
|
||||
const trimmedOrNull = (v: string) => (v.trim() ? v.trim() : null)
|
||||
|
||||
let bank_details: Record<string, unknown> | null = null
|
||||
if (form.bank_details.trim()) {
|
||||
try {
|
||||
bank_details = JSON.parse(form.bank_details)
|
||||
} catch {
|
||||
setBankError('Банковские реквизиты должны быть корректным JSON')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const payload: UpdateOrganizationRequest = {
|
||||
name: form.name.trim(),
|
||||
short_name: trimmedOrNull(form.short_name),
|
||||
@@ -87,14 +73,12 @@ export function useOrganizationForm(
|
||||
contact_person: trimmedOrNull(form.contact_person),
|
||||
contact_phone: trimmedOrNull(form.contact_phone),
|
||||
status: trimmedOrNull(form.status),
|
||||
bank_details,
|
||||
}
|
||||
|
||||
mutation.mutate(payload, { onSuccess: () => onSaved?.() })
|
||||
}
|
||||
|
||||
const error =
|
||||
bankError ?? (mutation.isError ? extractErrorMessage(mutation.error) : null)
|
||||
const error = mutation.isError ? extractErrorMessage(mutation.error) : null
|
||||
|
||||
return {
|
||||
form,
|
||||
|
||||
@@ -39,6 +39,11 @@
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.documents {
|
||||
max-width: 900px;
|
||||
margin: 24px auto 0;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useAdminAuth, useOrganization } from '@features/admin'
|
||||
import { ROUTES } from '@shared/config/routes'
|
||||
import { FormField, Notification, PrimaryButton } from '@shared/ui'
|
||||
import { AdminLoginForm } from '@widgets/admin-login-form'
|
||||
import { OrganizationDocuments } from '@widgets/organization-documents'
|
||||
import { useOrganizationForm } from '../model/useOrganizationForm'
|
||||
import styles from './AdminOrganizationPage.module.css'
|
||||
|
||||
@@ -71,19 +72,6 @@ export function AdminOrganizationPage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>Банковские реквизиты</h2>
|
||||
<label className={styles.bankLabel}>JSON-объект реквизитов</label>
|
||||
<textarea
|
||||
className={styles.textarea}
|
||||
value={form.bank_details}
|
||||
onChange={(e) => setField('bank_details')(e.target.value)}
|
||||
placeholder={'{\n "bank_name": "...",\n "bik": "...",\n "account": "..."\n}'}
|
||||
rows={6}
|
||||
spellCheck={false}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>Системная информация</h2>
|
||||
<div className={styles.grid}>
|
||||
@@ -105,6 +93,12 @@ export function AdminOrganizationPage() {
|
||||
</form>
|
||||
)}
|
||||
|
||||
{org && (
|
||||
<div className={styles.documents}>
|
||||
<OrganizationDocuments orgId={org.id} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{notice && (
|
||||
<Notification
|
||||
status="success"
|
||||
|
||||
@@ -1,16 +1,40 @@
|
||||
import { useState } from 'react'
|
||||
import { useAdminAuth, useAdminLogout } from '@features/admin'
|
||||
import { useAdminAuth, useAdminLogout, useCreateOrganizationWallets } from '@features/admin'
|
||||
import type { Organization } from '@features/admin'
|
||||
import { Notification } from '@shared/ui'
|
||||
import { AdminLoginForm } from '@widgets/admin-login-form'
|
||||
import { LegalEntitiesTable } from '@widgets/legal-entities-table'
|
||||
import { AddLegalEntityModal } from '@widgets/add-legal-entity-modal'
|
||||
import styles from './AdminPage.module.css'
|
||||
|
||||
type NotificationState = { message: string; status: 'success' | 'error' | 'warning' }
|
||||
|
||||
export function AdminPage() {
|
||||
const { isAuthenticated, isLoading } = useAdminAuth()
|
||||
const logout = useAdminLogout()
|
||||
const createWallets = useCreateOrganizationWallets()
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
const [notification, setNotification] = useState<{ message: string; status: 'success' | 'error' } | null>(null)
|
||||
const [notification, setNotification] = useState<NotificationState | null>(null)
|
||||
|
||||
// After a legal entity is created we immediately provision its wallets.
|
||||
// The page stays mounted (unlike the modal), so these mutate callbacks fire reliably.
|
||||
function handleCreated(organization: Organization) {
|
||||
setNotification({ status: 'success', message: 'Юридическое лицо добавлено' })
|
||||
createWallets.mutate(organization.id, {
|
||||
onSuccess: (wallets) => {
|
||||
setNotification({
|
||||
status: 'success',
|
||||
message: `Кошельки созданы (${wallets.length})`,
|
||||
})
|
||||
},
|
||||
onError: () => {
|
||||
setNotification({
|
||||
status: 'warning',
|
||||
message: 'Юридическое лицо создано, но кошельки создать не удалось',
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (isLoading) return null
|
||||
if (!isAuthenticated) return <AdminLoginForm />
|
||||
@@ -38,7 +62,7 @@ export function AdminPage() {
|
||||
<AddLegalEntityModal
|
||||
open={modalOpen}
|
||||
onClose={() => setModalOpen(false)}
|
||||
onCreated={() => setNotification({ status: 'success', message: 'Юридическое лицо добавлено' })}
|
||||
onCreated={handleCreated}
|
||||
/>
|
||||
|
||||
{notification && (
|
||||
|
||||
Reference in New Issue
Block a user