Skip to content

Commit 7af80d9

Browse files
authored
Merge pull request #1022 from topcoder-platform/diazz-code-30376369
Topcoder Admin App - Billing Account Management
2 parents 1e47bf8 + 757c086 commit 7af80d9

File tree

86 files changed

+5684
-14
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+5684
-14
lines changed

src/apps/admin/src/admin-app.routes.tsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '~/libs/core'
99

1010
import {
11+
billingAccountRouteId,
1112
manageChallengeRouteId,
1213
manageReviewRouteId,
1314
permissionManagementRouteId,
@@ -43,6 +44,37 @@ const ManageReviewerPage: LazyLoadedComponent = lazyLoad(
4344
() => import('./review-management/ManageReviewerPage'),
4445
'ManageReviewerPage',
4546
)
47+
const BillingAccount: LazyLoadedComponent = lazyLoad(
48+
() => import('./billing-account/BillingAccount'),
49+
)
50+
const BillingAccountsPage: LazyLoadedComponent = lazyLoad(
51+
() => import('./billing-account/BillingAccountsPage'),
52+
'BillingAccountsPage',
53+
)
54+
const BillingAccountNewPage: LazyLoadedComponent = lazyLoad(
55+
() => import('./billing-account/BillingAccountNewPage'),
56+
'BillingAccountNewPage',
57+
)
58+
const BillingAccountDetailsPage: LazyLoadedComponent = lazyLoad(
59+
() => import('./billing-account/BillingAccountDetailsPage'),
60+
'BillingAccountDetailsPage',
61+
)
62+
const BillingAccountResourcesPage: LazyLoadedComponent = lazyLoad(
63+
() => import('./billing-account/BillingAccountResourcesPage'),
64+
'BillingAccountResourcesPage',
65+
)
66+
const BillingAccountResourceNewPage: LazyLoadedComponent = lazyLoad(
67+
() => import('./billing-account/BillingAccountResourceNewPage'),
68+
'BillingAccountResourceNewPage',
69+
)
70+
const ClientsPage: LazyLoadedComponent = lazyLoad(
71+
() => import('./billing-account/ClientsPage'),
72+
'ClientsPage',
73+
)
74+
const ClientEditPage: LazyLoadedComponent = lazyLoad(
75+
() => import('./billing-account/ClientEditPage'),
76+
'ClientEditPage',
77+
)
4678
const PermissionManagement: LazyLoadedComponent = lazyLoad(
4779
() => import('./permission-management/PermissionManagement'),
4880
)
@@ -124,6 +156,59 @@ export const adminRoutes: ReadonlyArray<PlatformRoute> = [
124156
id: manageReviewRouteId,
125157
route: manageReviewRouteId,
126158
},
159+
// Billing Account Module
160+
{
161+
children: [
162+
{
163+
element: <BillingAccountsPage />,
164+
id: 'billing-accounts-page',
165+
route: 'billing-accounts',
166+
},
167+
{
168+
element: <BillingAccountNewPage />,
169+
id: 'billing-account-new-page',
170+
route: 'billing-accounts/new',
171+
},
172+
{
173+
element: <BillingAccountDetailsPage />,
174+
id: 'billing-account-details-page',
175+
route: 'billing-accounts/:accountId/details',
176+
},
177+
{
178+
element: <BillingAccountResourcesPage />,
179+
id: 'billing-account-resources-page',
180+
route: 'billing-accounts/:accountId/resources',
181+
},
182+
{
183+
element: <BillingAccountNewPage />,
184+
id: 'billing-account-resources-page',
185+
route: 'billing-accounts/:accountId/edit',
186+
},
187+
{
188+
element: <BillingAccountResourceNewPage />,
189+
id: 'billing-account-resource-new-page',
190+
route: 'billing-accounts/:accountId/resources/new',
191+
},
192+
{
193+
element: <ClientsPage />,
194+
id: 'billing-account-clients-page',
195+
route: 'clients',
196+
},
197+
{
198+
element: <ClientEditPage />,
199+
id: 'billing-account-client-edit-page',
200+
route: 'clients/:clientId/edit',
201+
},
202+
{
203+
element: <ClientEditPage />,
204+
id: 'billing-account-client-edit-page',
205+
route: 'clients/new',
206+
},
207+
],
208+
element: <BillingAccount />,
209+
id: billingAccountRouteId,
210+
route: billingAccountRouteId,
211+
},
127212
// Permission Management Module
128213
{
129214
children: [
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { FC, PropsWithChildren, useContext, useMemo } from 'react'
2+
import { Outlet, Routes } from 'react-router-dom'
3+
4+
import { routerContext, RouterContextData } from '~/libs/core'
5+
6+
import { Layout } from '../lib/components'
7+
import { adminRoutes } from '../admin-app.routes'
8+
import { billingAccountRouteId } from '../config/routes.config'
9+
10+
/**
11+
* The router outlet with layout.
12+
*/
13+
export const BillingAccount: FC & {
14+
Layout: FC<PropsWithChildren>
15+
} = () => {
16+
const childRoutes = useChildRoutes()
17+
18+
return (
19+
<>
20+
<Outlet />
21+
<Routes>{childRoutes}</Routes>
22+
</>
23+
)
24+
}
25+
26+
function useChildRoutes(): Array<JSX.Element> | undefined {
27+
const { getRouteElement }: RouterContextData = useContext(routerContext)
28+
const childRoutes = useMemo(
29+
() => adminRoutes[0].children
30+
?.find(r => r.id === billingAccountRouteId)
31+
?.children?.map(getRouteElement),
32+
[], // eslint-disable-line react-hooks/exhaustive-deps -- missing dependency: getRouteElement
33+
)
34+
return childRoutes
35+
}
36+
37+
/**
38+
* The outlet layout.
39+
*/
40+
BillingAccount.Layout = function BillingAccountLayout(
41+
props: PropsWithChildren,
42+
) {
43+
return <Layout>{props.children}</Layout>
44+
}
45+
46+
export default BillingAccount
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
@import '@libs/ui/styles/includes';
2+
3+
.container {
4+
display: flex;
5+
flex-direction: column;
6+
}
7+
8+
.loadingSpinnerContainer {
9+
position: relative;
10+
height: 100px;
11+
12+
.spinner {
13+
background: none;
14+
}
15+
}
16+
17+
.blockBottom {
18+
display: flex;
19+
justify-content: flex-end;
20+
align-items: flex-start;
21+
flex-wrap: wrap;
22+
gap: 30px;
23+
margin-left: auto;
24+
margin-top: $sp-2;
25+
26+
@include ltemd {
27+
flex-direction: column;
28+
align-items: flex-end;
29+
}
30+
}
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/**
2+
* Billing account details page.
3+
*/
4+
import { FC, useMemo } from 'react'
5+
import { useParams } from 'react-router-dom'
6+
import classNames from 'classnames'
7+
8+
import { LinkButton, LoadingSpinner, PageTitle } from '~/libs/ui'
9+
10+
import { DetailsTableColumn } from '../../lib/models/DetailsTableColumn.model'
11+
import { useManageBillingAccountDetail, useManageBillingAccountDetailProps } from '../../lib/hooks'
12+
import { PageContent, PageHeader } from '../../lib'
13+
import { BillingAccount } from '../../lib/models'
14+
import { TableRowDetails } from '../../lib/components/common/TableRowDetails'
15+
16+
import styles from './BillingAccountDetailsPage.module.scss'
17+
18+
interface Props {
19+
className?: string
20+
}
21+
22+
const pageTitle = 'Details - Billing Account'
23+
24+
export const BillingAccountDetailsPage: FC<Props> = (props: Props) => {
25+
const { accountId = '' }: { accountId?: string } = useParams<{
26+
accountId: string
27+
}>()
28+
const { isLoading, billingAccount }: useManageBillingAccountDetailProps
29+
= useManageBillingAccountDetail(accountId)
30+
31+
const columns = useMemo<DetailsTableColumn<BillingAccount>[][]>(
32+
() => [
33+
[
34+
{
35+
detailType: 'label',
36+
label: 'Name label',
37+
propertyName: 'name',
38+
renderer: () => <div>Name</div>,
39+
type: 'element',
40+
},
41+
{
42+
label: 'Name',
43+
propertyName: 'name',
44+
type: 'text',
45+
},
46+
],
47+
[
48+
{
49+
detailType: 'label',
50+
label: 'Customer Number label',
51+
propertyName: 'companyId',
52+
renderer: () => <div>Customer Number</div>,
53+
type: 'element',
54+
},
55+
{
56+
label: 'Customer Number',
57+
propertyName: 'companyId',
58+
type: 'text',
59+
},
60+
],
61+
[
62+
{
63+
detailType: 'label',
64+
label: 'Start Date label',
65+
propertyName: 'startDateString',
66+
renderer: () => <div>Start Date</div>,
67+
type: 'element',
68+
},
69+
{
70+
label: 'Start Date',
71+
propertyName: 'startDateString',
72+
type: 'text',
73+
},
74+
],
75+
[
76+
{
77+
detailType: 'label',
78+
label: 'End Date label',
79+
propertyName: 'endDateString',
80+
renderer: () => <div>End Date</div>,
81+
type: 'element',
82+
},
83+
{
84+
label: 'End Date',
85+
propertyName: 'endDateString',
86+
type: 'text',
87+
},
88+
],
89+
[
90+
{
91+
detailType: 'label',
92+
label: 'Status label',
93+
propertyName: 'status',
94+
renderer: () => <div>Status</div>,
95+
type: 'element',
96+
},
97+
{
98+
label: 'Status',
99+
propertyName: 'status',
100+
type: 'text',
101+
},
102+
],
103+
[
104+
{
105+
detailType: 'label',
106+
label: 'Amount label',
107+
propertyName: 'budgetAmount',
108+
renderer: () => <div>Amount</div>,
109+
type: 'element',
110+
},
111+
{
112+
label: 'Amount',
113+
propertyName: 'budgetAmount',
114+
type: 'text',
115+
},
116+
],
117+
[
118+
{
119+
detailType: 'label',
120+
label: 'PO Number label',
121+
propertyName: 'poNumber',
122+
renderer: () => <div>PO Number</div>,
123+
type: 'element',
124+
},
125+
{
126+
label: 'PO Number',
127+
propertyName: 'poNumber',
128+
type: 'text',
129+
},
130+
],
131+
[
132+
{
133+
detailType: 'label',
134+
label: 'Subscription Number label',
135+
propertyName: 'subscriptionNumber',
136+
renderer: () => <div>Subscription Number</div>,
137+
type: 'element',
138+
},
139+
{
140+
label: 'Subscription Number',
141+
propertyName: 'subscriptionNumber',
142+
type: 'text',
143+
},
144+
],
145+
[
146+
{
147+
detailType: 'label',
148+
label: 'Description label',
149+
propertyName: 'description',
150+
renderer: () => <div>Description</div>,
151+
type: 'element',
152+
},
153+
{
154+
label: 'Description',
155+
propertyName: 'description',
156+
type: 'text',
157+
},
158+
],
159+
[
160+
{
161+
detailType: 'label',
162+
label: 'Payment Terms label',
163+
propertyName: 'paymentTerms',
164+
renderer: () => <div>Payment Terms</div>,
165+
type: 'element',
166+
},
167+
{
168+
label: 'Payment Terms',
169+
propertyName: 'paymentTerms',
170+
type: 'text',
171+
},
172+
],
173+
],
174+
[],
175+
)
176+
return (
177+
<div className={classNames(styles.container, props.className)}>
178+
<PageTitle>{pageTitle}</PageTitle>
179+
<PageHeader>
180+
<h3>{pageTitle}</h3>
181+
</PageHeader>
182+
183+
<PageContent>
184+
{isLoading || !billingAccount ? (
185+
<div className={styles.loadingSpinnerContainer}>
186+
<LoadingSpinner className={styles.spinner} />
187+
</div>
188+
) : (
189+
<TableRowDetails data={billingAccount} columns={columns} />
190+
)}
191+
</PageContent>
192+
<div className={styles.blockBottom}>
193+
<LinkButton primary light to='./../..' size='lg'>
194+
Cancel
195+
</LinkButton>
196+
</div>
197+
</div>
198+
)
199+
}
200+
201+
export default BillingAccountDetailsPage
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as BillingAccountDetailsPage } from './BillingAccountDetailsPage'

0 commit comments

Comments
 (0)