Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
733ffc5
PM-5308 - projects showcase posts table
vas3a Jun 25, 2026
22be298
PM-5308 - update UI for projects showcase table
vas3a Jun 25, 2026
be3c347
lint
vas3a Jun 25, 2026
28af031
PM-5309 - projects showcase post management
vas3a Jun 26, 2026
3553b3b
lint
vas3a Jun 26, 2026
4d34796
Merge pull request #1990 from topcoder-platform/PM-5308_project-showc…
vas3a Jun 26, 2026
84a41d7
Merge pull request #1993 from topcoder-platform/PM-5309_projects-show…
vas3a Jun 26, 2026
3d05a03
Merge pull request #1994 from topcoder-platform/PM-5308_project-showc…
vas3a Jun 26, 2026
004f7f3
PM-5309 - minor css fix
vas3a Jun 26, 2026
0475982
Merge pull request #1995 from topcoder-platform/PM-5309_projects-show…
vas3a Jun 26, 2026
f53d991
Initial procurement app
jmgasper Jun 29, 2026
75243ff
PM-5309 qa feedback
vas3a Jun 29, 2026
d087dc0
PM-5309 - allow multiple challenges for showcase post
vas3a Jun 29, 2026
7f727fc
Merge pull request #1996 from topcoder-platform/PM-5309_post-manageme…
vas3a Jun 29, 2026
099a782
Merge pull request #1997 from topcoder-platform/procurement
jmgasper Jun 30, 2026
69f9b43
PM-5485 - media assets for project showcase
vas3a Jun 30, 2026
4406859
Pr feedback
vas3a Jun 30, 2026
2d9e724
Merge pull request #1998 from topcoder-platform/PM-5485_showcase-post…
vas3a Jun 30, 2026
0d111d9
Fix local testing URL for procurement
jmgasper Jun 30, 2026
2780507
PM-5458: Use placement history for profile win counts
jmgasper Jul 1, 2026
6b453cf
PM-5308 show project name
vas3a Jul 1, 2026
3409bb0
PM-5308 - qa fixes
vas3a Jul 1, 2026
173a349
PM-5309 - qa fixes
vas3a Jul 1, 2026
d337ef7
lint
vas3a Jul 1, 2026
1ef4d17
Merge pull request #2000 from topcoder-platform/PM-5308_project-showc…
vas3a Jul 1, 2026
5a3a2d2
align
vas3a Jul 1, 2026
b781a24
Merge pull request #2001 from topcoder-platform/PM-5308_project-showc…
vas3a Jul 1, 2026
06d1f42
PM-5485 - update meida post preview
vas3a Jul 1, 2026
786bec2
PM-5489: Allow challenge resources to view Work challenges
jmgasper Jul 1, 2026
1ea45fb
PM-5486 - fix upload media
vas3a Jul 1, 2026
c008b4c
fix role check
vas3a Jul 1, 2026
b9054a7
lint
vas3a Jul 1, 2026
d98cb63
Merge pull request #2003 from topcoder-platform/PM-5308_project-showc…
vas3a Jul 1, 2026
e98ed86
fix css for empty state
vas3a Jul 1, 2026
cceedfd
Merge pull request #2004 from topcoder-platform/PM-5308_project-showc…
vas3a Jul 1, 2026
f3ddd20
PM-5487 - use topcoder cdn and use signed urls
vas3a Jul 1, 2026
d6fcd39
Merge branch 'dev' of github.com:topcoder-platform/platform-ui into P…
vas3a Jul 1, 2026
d700e28
PM-5487 - show signed url immediately after upload
vas3a Jul 1, 2026
2605c5a
lint
vas3a Jul 1, 2026
224ec05
Merge pull request #2005 from topcoder-platform/PM-5487_showcase-medi…
vas3a Jul 1, 2026
b9b1bbd
Merge pull request #2002 from topcoder-platform/PM-5489
jmgasper Jul 1, 2026
ba7e581
Merge pull request #1999 from topcoder-platform/PM-5458
jmgasper Jul 1, 2026
d3ca44e
PM-5511: Add submission ID filter
jmgasper Jul 1, 2026
30f55d5
PM-5510: Add marathon submission test type filter
jmgasper Jul 1, 2026
1785748
Merge pull request #2007 from topcoder-platform/PM-5510
jmgasper Jul 2, 2026
135e690
Merge remote-tracking branch 'origin/dev' into PM-5511
jmgasper Jul 2, 2026
a4351da
Merge pull request #2006 from topcoder-platform/PM-5511
jmgasper Jul 2, 2026
f657aba
PM-5503: Support multi-status engagement filter
jmgasper Jul 2, 2026
4d70bbc
PM-5506: Link missing member terms in work save errors
jmgasper Jul 2, 2026
e0b8cf0
PM-5245: Prefer finance engagement splits
jmgasper Jul 2, 2026
7fee8ac
PM-5504: Allow private engagements without assignees
jmgasper Jul 2, 2026
75d71e9
Fixes for the billing account details popup in PM-5507
jmgasper Jul 2, 2026
4434f07
Merge pull request #2013 from topcoder-platform/PM-5507-1
jmgasper Jul 2, 2026
e49dc1c
Merge pull request #2012 from topcoder-platform/PM-5504
jmgasper Jul 3, 2026
d431e5f
Merge pull request #2008 from topcoder-platform/PM-5503
jmgasper Jul 3, 2026
1750bb6
Merge pull request #2009 from topcoder-platform/PM-5506
jmgasper Jul 3, 2026
3b0ba01
Merge pull request #2011 from topcoder-platform/PM-5245-2
jmgasper Jul 3, 2026
244248c
PM-5504: Allow blank private member slots
jmgasper Jul 3, 2026
2434946
Merge pull request #2014 from topcoder-platform/PM-5504-1
jmgasper Jul 3, 2026
d3634a0
PM-5309 - fix user role check for project managers
vas3a Jul 3, 2026
5897a59
Support for upload type for PM-5516
jmgasper Jul 3, 2026
8d3c840
lint
vas3a Jul 3, 2026
6b9a04d
Merge pull request #2016 from topcoder-platform/PM-5309_fix-user-role
vas3a Jul 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/apps/platform/src/platform.routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { workRoutes } from '~/apps/work'
import { calendarRoutes } from '~/apps/calendar'
import { engagementsRoutes } from '~/apps/engagements'
import { customerPortalRoutes } from '~/apps/customer-portal'
import { procurementRoutes } from '~/apps/procurement'

const Home: LazyLoadedComponent = lazyLoad(
() => import('./routes/home'),
Expand Down Expand Up @@ -45,6 +46,7 @@ export const platformRoutes: Array<PlatformRoute> = [
...workRoutes,
...calendarRoutes,
...engagementsRoutes,
...procurementRoutes,
...homeRoutes,
...adminRoutes,
...reportsRoutes,
Expand Down
1 change: 1 addition & 0 deletions src/apps/procurement/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src'
65 changes: 65 additions & 0 deletions src/apps/procurement/src/ProcurementApp.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.outer {
padding-top: 24px;
}

.inner {
max-width: 1280px;
}

.navigation {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0 0 24px;
padding: 4px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: #f9fafb;
}

.navigationLink {
display: inline-flex;
align-items: center;
min-height: 36px;
padding: 8px 14px;
border-radius: 6px;
color: #374151;
font-size: 14px;
font-weight: 700;
line-height: 1.2;
text-decoration: none;

&:hover {
background: #ffffff;
color: #0f766e;
}
}

.active {
background: #0f766e;
color: #ffffff;

&:hover {
background: #0f766e;
color: #ffffff;
}
}

.content {
min-width: 0;
}

@media (max-width: 720px) {
.outer {
padding-top: 16px;
}

.navigation {
gap: 4px;
}

.navigationLink {
flex: 1 1 120px;
justify-content: center;
}
}
91 changes: 91 additions & 0 deletions src/apps/procurement/src/ProcurementApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-disable react/jsx-no-bind */
/**
* Shell for the hidden procurement app.
*/
import { FC, useContext, useMemo } from 'react'
import { NavLink, Outlet, Routes } from 'react-router-dom'
import classNames from 'classnames'

import { routerContext, RouterContextData } from '~/libs/core'
import { ContentLayout } from '~/libs/ui'

import {
buildProcurementPath,
procurementContractsRoute,
procurementDashboardRoute,
procurementInvoicesRoute,
procurementRenewalsRoute,
procurementVendorsRoute,
} from './config/routes.config'
import { toolTitle } from './procurement-app.routes'
import styles from './ProcurementApp.module.scss'

interface ProcurementNavigationItem {
label: string
route: string
to: string
}

const navigationItems: ProcurementNavigationItem[] = [
{
label: 'Dashboard',
route: procurementDashboardRoute,
to: buildProcurementPath(procurementDashboardRoute),
},
{
label: 'Vendors',
route: procurementVendorsRoute,
to: buildProcurementPath(procurementVendorsRoute),
},
{
label: 'Contracts',
route: procurementContractsRoute,
to: buildProcurementPath(procurementContractsRoute),
},
{
label: 'Invoices',
route: procurementInvoicesRoute,
to: buildProcurementPath(procurementInvoicesRoute),
},
{
label: 'Renewals',
route: procurementRenewalsRoute,
to: buildProcurementPath(procurementRenewalsRoute),
},
]

const ProcurementApp: FC = () => {
const { getChildRoutes }: RouterContextData = useContext(routerContext)
const childRoutes = useMemo(() => getChildRoutes(toolTitle), [getChildRoutes])

return (
<ContentLayout
innerClass={styles.inner}
outerClass={styles.outer}
title='Procurement'
>
<nav aria-label='Procurement modules' className={styles.navigation}>
{navigationItems.map((item: ProcurementNavigationItem) => (
<NavLink
className={({ isActive }: { isActive: boolean }) => classNames(
styles.navigationLink,
{ [styles.active]: isActive },
)}
end={item.route === procurementDashboardRoute}
key={item.route || 'dashboard'}
to={item.to}
>
{item.label}
</NavLink>
))}
</nav>

<div className={styles.content}>
<Outlet />
<Routes>{childRoutes}</Routes>
</div>
</ContentLayout>
)
}

export default ProcurementApp
37 changes: 37 additions & 0 deletions src/apps/procurement/src/config/routes.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Common config for routes in procurement app.
*/
import { AppSubdomain, EnvironmentConfig } from '~/config'

export const rootRoute: string
= EnvironmentConfig.SUBDOMAIN === AppSubdomain.procurement
? ''
: `/${AppSubdomain.procurement}`

export const procurementContractsRouteId = 'procurement-contracts'
export const procurementDashboardRouteId = 'procurement-dashboard'
export const procurementInvoicesRouteId = 'procurement-invoices'
export const procurementRenewalsRouteId = 'procurement-renewals'
export const procurementVendorsRouteId = 'procurement-vendors'

export const procurementDashboardRoute = ''
export const procurementContractsRoute = 'contracts'
export const procurementInvoicesRoute = 'invoices'
export const procurementRenewalsRoute = 'renewals'
export const procurementVendorsRoute = 'vendors'

/**
* Builds an absolute procurement path from a child route segment.
*
* @param route Child route segment from the procurement route map.
* @returns Absolute path rooted at the configured procurement root route.
*/
export function buildProcurementPath(route: string = procurementDashboardRoute): string {
const normalizedRoute: string = route.replace(/^\/+/, '')

if (!normalizedRoute) {
return rootRoute || '/'
}

return `${rootRoute}/${normalizedRoute}`
}
2 changes: 2 additions & 0 deletions src/apps/procurement/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { procurementRoutes } from './procurement-app.routes'
export { rootRoute as procurementRootRoute } from './config/routes.config'
12 changes: 12 additions & 0 deletions src/apps/procurement/src/lib/constants/roles.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Procurement role constants accepted by the procurement app routes.
*/
export const ProcurementRole = {
admin: 'procurement-admin',
user: 'procurement-user',
} as const

export const PROCUREMENT_ALLOWED_ROLES: Array<string> = [
ProcurementRole.admin,
ProcurementRole.user,
]
47 changes: 47 additions & 0 deletions src/apps/procurement/src/lib/models/contract.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ContractLifecycle, ContractStatus } from './procurement-common.model'

/**
* Vendor summary embedded in contract responses.
*/
export interface ContractVendorSummary {
category?: string
id: string
name: string
}

/**
* Contract read model with stored status and backend-derived lifecycle.
*/
export interface Contract {
autoRenew: boolean
contractNumber: string
createdAt: string
description?: string
endDate: string
id: string
lifecycle: ContractLifecycle
renewalNoticeDays?: number | null
startDate: string
status: ContractStatus
title: string
updatedAt: string
value: number
vendor: ContractVendorSummary
vendorId: string
}

/**
* Editable contract fields accepted by create and update endpoints.
*/
export interface ContractMutationPayload {
autoRenew?: boolean
contractNumber: string
description?: string
endDate: string
renewalNoticeDays?: number
startDate: string
status?: ContractStatus
title: string
value: number
vendorId: string
}
16 changes: 16 additions & 0 deletions src/apps/procurement/src/lib/models/dashboard-summary.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Contract } from './contract.model'

/**
* Summary response returned by the procurement dashboard endpoint.
*/
export interface DashboardSummary {
activeContractCount: number
activeRenewalCount: number
expiringContractCount: number
expiringContracts: Contract[]
overdueInvoiceCount: number
overdueInvoiceTotal: number
pendingInvoiceCount: number
pendingInvoiceTotal: number
vendorCount: number
}
6 changes: 6 additions & 0 deletions src/apps/procurement/src/lib/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './contract.model'
export * from './dashboard-summary.model'
export * from './invoice.model'
export * from './procurement-common.model'
export * from './renewal.model'
export * from './vendor.model'
54 changes: 54 additions & 0 deletions src/apps/procurement/src/lib/models/invoice.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { InvoicePaymentState, InvoiceStatus } from './procurement-common.model'

/**
* Contract summary embedded in invoice responses.
*/
export interface InvoiceContractSummary {
contractNumber: string
id: string
title: string
}

/**
* Vendor summary embedded in invoice responses.
*/
export interface InvoiceVendorSummary {
id: string
name: string
}

/**
* Invoice read model with stored status and backend-derived payment state.
*/
export interface Invoice {
amount: number
contract?: InvoiceContractSummary
contractId?: string
createdAt: string
description?: string
dueDate: string
id: string
invoiceDate: string
invoiceNumber: string
paidDate?: string
paymentState: InvoicePaymentState
status: InvoiceStatus
updatedAt: string
vendor: InvoiceVendorSummary
vendorId: string
}

/**
* Editable invoice fields accepted by create and update endpoints.
*/
export interface InvoiceMutationPayload {
amount: number
contractId?: string
description?: string
dueDate: string
invoiceDate: string
invoiceNumber: string
paidDate?: string
status?: InvoiceStatus
vendorId: string
}
20 changes: 20 additions & 0 deletions src/apps/procurement/src/lib/models/procurement-common.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Shared procurement enum-like frontend types returned by the procurement API.
*/
export type ContractLifecycle = 'active' | 'draft' | 'expired' | 'expiring' | 'terminated'

export type ContractStatus = 'active' | 'draft' | 'expired' | 'terminated'

export type InvoicePaymentState = 'cancelled' | 'draft' | 'overdue' | 'paid' | 'pending'

export type InvoiceStatus = 'cancelled' | 'draft' | 'issued' | 'paid'

export type RenewalStage =
| 'cio_approval'
| 'legal_review'
| 'order_form_signed'
| 'po_release'
| 'pr_approvals'
| 'pr_creation'
| 'quotation'
| 'vra'
Loading
Loading