fix
This commit is contained in:
@@ -3,12 +3,13 @@ import type {
|
||||
AdminLoginResponse,
|
||||
AdminMeResponse,
|
||||
CreateOrganizationRequest,
|
||||
CreateWalletsResponse,
|
||||
WalletResponse,
|
||||
DocumentResponse,
|
||||
Organization,
|
||||
OrganizationListResponse,
|
||||
PurchaseRequestListResponse,
|
||||
UpdateOrganizationRequest,
|
||||
WalletResponse,
|
||||
} from '../model/types'
|
||||
|
||||
const ADMIN_API_URL = 'https://app.admin.elcsa.ru'
|
||||
@@ -113,10 +114,18 @@ export function getOrganization(id: string): Promise<Organization> {
|
||||
return doAdminRequest<Organization>(`/v1/organizations/${id}`, {}, true)
|
||||
}
|
||||
|
||||
export function createOrganizationWallets(id: string): Promise<WalletResponse[]> {
|
||||
return doAdminRequest<WalletResponse[]>(
|
||||
export function createOrganizationWallets(id: string): Promise<CreateWalletsResponse> {
|
||||
return doAdminRequest<CreateWalletsResponse>(
|
||||
`/v1/organizations/${id}/wallets/create`,
|
||||
{ method: 'POST' },
|
||||
{ method: 'POST', body: JSON.stringify({ id }) },
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
export function getOrganizationWallets(id: string): Promise<WalletResponse[]> {
|
||||
return doAdminRequest<WalletResponse[]>(
|
||||
`/v1/organizations/${id}/wallets`,
|
||||
{},
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { createOrganizationWallets } from '../api/adminApi'
|
||||
import { ORGANIZATIONS_QUERY_KEY } from './useOrganizations'
|
||||
import { ORGANIZATION_QUERY_KEY } from './useOrganization'
|
||||
import { WALLETS_QUERY_KEY } from './useOrganizationWallets'
|
||||
|
||||
export function useCreateOrganizationWallets() {
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: (organizationId: string) => createOrganizationWallets(organizationId),
|
||||
onSuccess: (_wallets, organizationId) => {
|
||||
onSuccess: (_result, organizationId) => {
|
||||
// `has_wallets` flips to true server-side — refresh list and detail view.
|
||||
queryClient.invalidateQueries({ queryKey: ORGANIZATIONS_QUERY_KEY })
|
||||
queryClient.invalidateQueries({ queryKey: ORGANIZATION_QUERY_KEY(organizationId) })
|
||||
queryClient.invalidateQueries({ queryKey: WALLETS_QUERY_KEY(organizationId) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
12
src/features/admin/hooks/useOrganizationWallets.ts
Normal file
12
src/features/admin/hooks/useOrganizationWallets.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { getOrganizationWallets } from '../api/adminApi'
|
||||
|
||||
export const WALLETS_QUERY_KEY = (orgId: string) => ['admin-wallets', orgId]
|
||||
|
||||
export function useOrganizationWallets(orgId: string | undefined) {
|
||||
return useQuery({
|
||||
queryKey: WALLETS_QUERY_KEY(orgId ?? ''),
|
||||
queryFn: () => getOrganizationWallets(orgId as string),
|
||||
enabled: !!orgId,
|
||||
})
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export {
|
||||
getOrganization,
|
||||
createOrganization,
|
||||
createOrganizationWallets,
|
||||
getOrganizationWallets,
|
||||
updateOrganization,
|
||||
getDocuments,
|
||||
uploadDocument,
|
||||
@@ -35,6 +36,7 @@ export { useOrganization, ORGANIZATION_QUERY_KEY } from './hooks/useOrganization
|
||||
export { useCreateOrganization } from './hooks/useCreateOrganization'
|
||||
export { useCreateOrganizationWallets } from './hooks/useCreateOrganizationWallets'
|
||||
export { useUpdateOrganization } from './hooks/useUpdateOrganization'
|
||||
export { useOrganizationWallets, WALLETS_QUERY_KEY } from './hooks/useOrganizationWallets'
|
||||
export { useDocuments, DOCUMENTS_QUERY_KEY } from './hooks/useDocuments'
|
||||
export { useUploadDocument } from './hooks/useUploadDocument'
|
||||
export { usePurchaseRequests, PURCHASE_REQUESTS_QUERY_KEY } from './hooks/usePurchaseRequests'
|
||||
|
||||
@@ -58,6 +58,15 @@ export interface WalletResponse {
|
||||
created_at: string | null
|
||||
}
|
||||
|
||||
export interface CreateWalletsRequest {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface CreateWalletsResponse {
|
||||
wallets: WalletResponse[]
|
||||
mnemonic: string
|
||||
}
|
||||
|
||||
export interface DocumentResponse {
|
||||
id: string
|
||||
organization_id: string
|
||||
|
||||
@@ -6,13 +6,15 @@ import { FormField, Notification, PrimaryButton } from '@shared/ui'
|
||||
import { AdminLoginForm } from '@widgets/admin-login-form'
|
||||
import { OrganizationDocuments } from '@widgets/organization-documents'
|
||||
import { OrganizationPurchaseRequests } from '@widgets/organization-purchase-requests'
|
||||
import { OrganizationWallets } from '@widgets/organization-wallets'
|
||||
import { useOrganizationForm } from '../model/useOrganizationForm'
|
||||
import styles from './AdminOrganizationPage.module.css'
|
||||
|
||||
type Tab = 'info' | 'documents' | 'requests'
|
||||
type Tab = 'info' | 'wallets' | 'documents' | 'requests'
|
||||
|
||||
const TABS: { id: Tab; label: string }[] = [
|
||||
{ id: 'info', label: 'Общая информация' },
|
||||
{ id: 'wallets', label: 'Кошельки' },
|
||||
{ id: 'documents', label: 'Документы' },
|
||||
{ id: 'requests', label: 'Заявки' },
|
||||
]
|
||||
@@ -118,6 +120,12 @@ export function AdminOrganizationPage() {
|
||||
</form>
|
||||
)}
|
||||
|
||||
{org && activeTab === 'wallets' && (
|
||||
<div className={styles.tabPanel}>
|
||||
<OrganizationWallets orgId={org.id} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{org && activeTab === 'documents' && (
|
||||
<div className={styles.tabPanel}>
|
||||
<OrganizationDocuments orgId={org.id} />
|
||||
|
||||
@@ -21,10 +21,10 @@ export function AdminPage() {
|
||||
function handleCreated(organization: Organization) {
|
||||
setNotification({ status: 'success', message: 'Юридическое лицо добавлено' })
|
||||
createWallets.mutate(organization.id, {
|
||||
onSuccess: (wallets) => {
|
||||
onSuccess: (result) => {
|
||||
setNotification({
|
||||
status: 'success',
|
||||
message: `Кошельки созданы (${wallets.length})`,
|
||||
message: `Кошельки созданы (${result.wallets.length})`,
|
||||
})
|
||||
},
|
||||
onError: () => {
|
||||
|
||||
1
src/widgets/organization-wallets/index.ts
Normal file
1
src/widgets/organization-wallets/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { OrganizationWallets } from './ui/OrganizationWallets'
|
||||
@@ -0,0 +1,52 @@
|
||||
.section {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 20px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 14px;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-secondary, rgba(255, 255, 255, 0.5));
|
||||
font-weight: 600;
|
||||
margin: 0 0 18px;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.table th {
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
padding: 0 16px 14px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: 14px 16px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-size: 13px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.state {
|
||||
padding: 32px 16px;
|
||||
text-align: center;
|
||||
color: var(--text-secondary, rgba(255, 255, 255, 0.6));
|
||||
font-size: 14px;
|
||||
}
|
||||
53
src/widgets/organization-wallets/ui/OrganizationWallets.tsx
Normal file
53
src/widgets/organization-wallets/ui/OrganizationWallets.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useOrganizationWallets } from '@features/admin'
|
||||
import styles from './OrganizationWallets.module.css'
|
||||
|
||||
interface Props {
|
||||
orgId: string
|
||||
}
|
||||
|
||||
function formatDate(value: string | null): string {
|
||||
if (!value) return '—'
|
||||
const d = new Date(value)
|
||||
if (Number.isNaN(d.getTime())) return '—'
|
||||
return d.toLocaleString('ru-RU')
|
||||
}
|
||||
|
||||
export function OrganizationWallets({ orgId }: Props) {
|
||||
const { data: wallets, isLoading, isError } = useOrganizationWallets(orgId)
|
||||
|
||||
return (
|
||||
<section className={styles.section}>
|
||||
<h2 className={styles.sectionTitle}>Кошельки</h2>
|
||||
|
||||
{isLoading && <div className={styles.state}>Загрузка...</div>}
|
||||
{isError && <div className={styles.state}>Не удалось загрузить кошельки</div>}
|
||||
|
||||
{wallets && wallets.length === 0 && (
|
||||
<div className={styles.state}>Кошельки ещё не созданы</div>
|
||||
)}
|
||||
|
||||
{wallets && wallets.length > 0 && (
|
||||
<table className={styles.table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Сеть</th>
|
||||
<th>Адрес</th>
|
||||
<th>Derivation path</th>
|
||||
<th>Создано</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{wallets.map((wallet) => (
|
||||
<tr key={wallet.id}>
|
||||
<td>{wallet.chain}</td>
|
||||
<td className={styles.mono}>{wallet.address}</td>
|
||||
<td className={styles.mono}>{wallet.derivation_path}</td>
|
||||
<td>{formatDate(wallet.created_at)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user