Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,45 @@ describe('PaymentView', () => {
expect(workLogRemarksLink.getAttribute('target'))
.toBe('_blank')
})

it('renders task details section for task payments', async () => {
const taskPayment: Winning = {
...payment,
description: 'Build a cool widget for the dashboard',
externalId: 'challenge-uuid-1',
type: 'task payment',
}

mockedFetchWinningPaymentDetails.mockResolvedValue({
paymentCreatorHandle: 'task-creator',
taskDetails: {
paymentApproverHandle: 'approver-handle',
projectId: '42',
projectName: 'My Awesome Project',
},
})

render(<PaymentView payment={taskPayment} />)

await waitFor(() => {
expect(mockedFetchWinningPaymentDetails)
.toHaveBeenCalledWith(taskPayment)
})

expect(await screen.findByRole('heading', { name: 'Task Details' }))
.toBeTruthy()

expect(await screen.findByRole('heading', { name: 'Task Details' }))
.toBeTruthy()
expect(await screen.findByText('task-creator'))
.toBeTruthy()
expect(await screen.findByText('approver-handle'))
.toBeTruthy()

const projectLink = await screen.findByRole('link', { name: 'My Awesome Project' })
expect(projectLink.getAttribute('href'))
.toBe('https://challenges.example.com/projects/42/challenges/challenge-uuid-1/view')
expect(projectLink.getAttribute('target'))
.toBe('_blank')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getMemberHandle,
} from '../../services/wallet'
import {
buildWorkAppChallengeUrl,
buildWorkManagerAssignmentUrl,
buildWorkManagerProjectUrl,
formatOptionalDate,
Expand All @@ -42,14 +43,15 @@ const PaymentView: React.FC<PaymentViewProps> = (props: PaymentViewProps) => {
const [paymentDetailsError, setPaymentDetailsError] = React.useState<string>()

const isEngagementPayment = props.payment.type.toLowerCase() === 'engagement payment'
const isTaskPayment = props.payment.type.toLowerCase() === 'task payment'
const hasEngagementDetails = Boolean(paymentDetails?.engagementDetails)

const handleToggleView = (newView: 'audit' | 'details' | 'external_transaction'): void => {
setView(newView)
}

React.useEffect(() => {
if (!isEngagementPayment) {
if (!isEngagementPayment && !isTaskPayment) {
setPaymentDetails(undefined)
setIsPaymentDetailsLoading(false)
setPaymentDetailsError(undefined)
Expand All @@ -70,7 +72,7 @@ const PaymentView: React.FC<PaymentViewProps> = (props: PaymentViewProps) => {
.catch(() => {
if (!ignore) {
setPaymentDetails(undefined)
setPaymentDetailsError('Unable to load engagement details.')
setPaymentDetailsError(isTaskPayment ? 'Unable to load task details.' : 'Unable to load engagement details.')
}
})
.finally(() => {
Expand All @@ -82,7 +84,7 @@ const PaymentView: React.FC<PaymentViewProps> = (props: PaymentViewProps) => {
return () => {
ignore = true
}
}, [isEngagementPayment, props.payment])
}, [isEngagementPayment, isTaskPayment, props.payment])

React.useEffect(() => {
if (view === 'audit') {
Expand Down Expand Up @@ -138,7 +140,9 @@ const PaymentView: React.FC<PaymentViewProps> = (props: PaymentViewProps) => {

const descriptionLink = isEngagementPayment
? buildWorkManagerAssignmentUrl(paymentDetails?.engagementDetails)
: `${TOPCODER_URL}/challenges/${props.payment.externalId}`
: isTaskPayment
? buildWorkAppChallengeUrl(paymentDetails?.taskDetails?.projectId, props.payment.externalId)
: `${TOPCODER_URL}/challenges/${props.payment.externalId}`
const projectLink = buildWorkManagerProjectUrl(paymentDetails?.engagementDetails)

return (
Expand Down Expand Up @@ -306,6 +310,67 @@ const PaymentView: React.FC<PaymentViewProps> = (props: PaymentViewProps) => {
</div>
)}

{isTaskPayment && (
<div className={styles.section}>
<h3 className={styles.sectionTitle}>Task Details</h3>
{isPaymentDetailsLoading
? <p className={styles.helperText}>Loading task details...</p>
: undefined}
{!isPaymentDetailsLoading && paymentDetailsError
? <p className={styles.helperText}>{paymentDetailsError}</p>
: undefined}
{!isPaymentDetailsLoading && !paymentDetailsError && (
<div className={styles.sectionGrid}>
<div className={styles.infoItem}>
<span className={styles.label}>Task Creator</span>
<p className={styles.value}>
{formatOptionalText(paymentDetails?.paymentCreatorHandle)}
</p>
</div>
<div className={styles.infoItem}>
<span className={styles.label}>Task Description</span>
<p className={styles.remarksValue}>
{props.payment.description
? props.payment.description.substring(0, 500)
: '-'}
</p>
</div>
<div className={styles.infoItem}>
<span className={styles.label}>Project Name</span>
{buildWorkAppChallengeUrl(
paymentDetails?.taskDetails?.projectId,
props.payment.externalId,
) && paymentDetails?.taskDetails?.projectName
? (
<a
className={styles.value}
href={buildWorkAppChallengeUrl(
paymentDetails.taskDetails.projectId,
props.payment.externalId,
)}
target='_blank'
rel='noreferrer'
>
{paymentDetails.taskDetails.projectName}
</a>
)
: (
<p className={styles.value}>
{formatOptionalText(paymentDetails?.taskDetails?.projectName)}
</p>
)}
</div>
<div className={styles.infoItem}>
<span className={styles.label}>Payment Approver</span>
<p className={styles.value}>
{formatOptionalText(paymentDetails?.taskDetails?.paymentApproverHandle)}
</p>
</div>
</div>
)}
</div>
)}

<div className={styles.infoItem}>
<Button onClick={() => handleToggleView('audit')} label='View Audit' />
{props.payment.status.toUpperCase() === 'PAID' && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ export function renderOptionalLinkedText(
return nodes
}

export function buildWorkAppChallengeUrl(
projectId?: string,
challengeId?: string,
): string | undefined {
if (!projectId || !challengeId) {
return undefined
}

const baseUrl = EnvironmentConfig.ADMIN.WORK_MANAGER_URL.replace(/\/$/, '')

return `${baseUrl}/projects/${projectId}/challenges/${challengeId}/view`
}

export function formatOptionalDate(
value?: string | null,
): string {
Expand Down
7 changes: 7 additions & 0 deletions src/apps/wallet-admin/src/lib/models/WinningDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,17 @@ export interface PaymentWorkLog {
remarks?: string
}

export interface PaymentTaskDetails {
projectId?: string
projectName?: string
paymentApproverHandle?: string
}

export interface WinningPaymentDetails {
engagementDetails?: PaymentEngagementDetails
paymentCreatorHandle?: string
workLog?: PaymentWorkLog
taskDetails?: PaymentTaskDetails
}

export interface Winning {
Expand Down
Loading