Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0657ee4

Browse files
committed
fix: prfeedback
1 parent 01ee409 commit 0657ee4

File tree

6 files changed

+204
-78
lines changed

6 files changed

+204
-78
lines changed

src/components/Payroll/PayrollHistory/PayrollHistory.stories.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,39 @@
11
import { action } from '@ladle/react'
2+
import type { Payroll } from '@gusto/embedded-api/models/components/payroll'
23
import { PayrollHistoryPresentation } from './PayrollHistoryPresentation'
34
import type { PayrollHistoryItem } from './PayrollHistory'
45

56
export default {
67
title: 'Domain/Payroll/PayrollHistory',
78
}
89

10+
const createMockPayroll = (id: string, processed: boolean, cancellable: boolean): Payroll =>
11+
({
12+
payrollUuid: id,
13+
processed,
14+
checkDate: '2024-12-08',
15+
external: false,
16+
offCycle: false,
17+
payrollDeadline: new Date('2024-12-07T23:30:00Z'),
18+
payrollStatusMeta: {
19+
cancellable,
20+
expectedCheckDate: '2024-12-08',
21+
initialCheckDate: '2024-12-08',
22+
expectedDebitTime: '2024-12-07T23:30:00Z',
23+
payrollLate: false,
24+
initialDebitCutoffTime: '2024-12-07T23:30:00Z',
25+
},
26+
payPeriod: {
27+
startDate: '2024-11-24',
28+
endDate: '2024-12-07',
29+
payScheduleUuid: 'schedule-1',
30+
},
31+
totals: {
32+
netPay: '30198.76',
33+
grossPay: '38000.00',
34+
},
35+
}) as Payroll
36+
937
const mockPayrollHistory: PayrollHistoryItem[] = [
1038
{
1139
id: '1',
@@ -14,6 +42,7 @@ const mockPayrollHistory: PayrollHistoryItem[] = [
1442
payDate: 'Dec 8, 2024',
1543
status: 'In progress',
1644
amount: 30198.76,
45+
payroll: createMockPayroll('1', false, true),
1746
},
1847
{
1948
id: '2',
@@ -22,6 +51,7 @@ const mockPayrollHistory: PayrollHistoryItem[] = [
2251
payDate: 'Dec 8, 2024',
2352
status: 'Unprocessed',
2453
amount: 30198.76,
54+
payroll: createMockPayroll('2', false, true),
2555
},
2656
{
2757
id: '3',
@@ -30,6 +60,7 @@ const mockPayrollHistory: PayrollHistoryItem[] = [
3060
payDate: 'Nov 24, 2024',
3161
status: 'Complete',
3262
amount: 30842.99,
63+
payroll: createMockPayroll('3', true, false),
3364
},
3465
{
3566
id: '4',
@@ -38,6 +69,7 @@ const mockPayrollHistory: PayrollHistoryItem[] = [
3869
payDate: 'Oct 1, 2024',
3970
status: 'Submitted',
4071
amount: 28456.5,
72+
payroll: createMockPayroll('4', false, true),
4173
},
4274
]
4375

src/components/Payroll/PayrollHistory/PayrollHistory.test.tsx

Lines changed: 9 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,7 @@ import { componentEvents } from '@/shared/constants'
88
import { setupApiTestMocks } from '@/test/mocks/apiServer'
99
import { renderWithProviders } from '@/test-utils/renderWithProviders'
1010
import { API_BASE_URL } from '@/test/constants'
11-
12-
// Mock data that matches the API structure (snake_case)
13-
const mockPayrollData = [
14-
{
15-
payroll_uuid: 'payroll-1',
16-
processed: true,
17-
check_date: '2024-12-15',
18-
external: false,
19-
off_cycle: false,
20-
pay_period: {
21-
start_date: '2024-12-01',
22-
end_date: '2024-12-15',
23-
pay_schedule_uuid: 'schedule-1',
24-
},
25-
totals: {
26-
net_pay: '2500.00',
27-
gross_pay: '3200.00',
28-
},
29-
},
30-
{
31-
payroll_uuid: 'payroll-2',
32-
processed: true,
33-
check_date: '2024-11-30',
34-
external: false,
35-
off_cycle: true,
36-
pay_period: {
37-
start_date: '2024-11-15',
38-
end_date: '2024-11-30',
39-
pay_schedule_uuid: 'schedule-1',
40-
},
41-
totals: {
42-
net_pay: '1800.00',
43-
gross_pay: '2300.00',
44-
},
45-
},
46-
{
47-
payroll_uuid: 'payroll-3',
48-
processed: true,
49-
check_date: '2024-11-15',
50-
external: true,
51-
off_cycle: false,
52-
pay_period: {
53-
start_date: '2024-11-01',
54-
end_date: '2024-11-15',
55-
pay_schedule_uuid: 'schedule-1',
56-
},
57-
totals: {
58-
net_pay: '3000.00',
59-
gross_pay: '3850.00',
60-
},
61-
},
62-
]
11+
import { getFixture } from '@/test/mocks/fixtures/getFixture'
6312

6413
const mockEmptyPayrollData: never[] = []
6514

@@ -71,11 +20,12 @@ describe('PayrollHistory', () => {
7120
onEvent,
7221
}
7322

74-
beforeEach(() => {
23+
beforeEach(async () => {
7524
setupApiTestMocks()
7625
onEvent.mockClear()
7726

78-
// Mock the payrolls list API
27+
// Mock the payrolls list API with fixture data
28+
const mockPayrollData = await getFixture('payroll-history-test-data')
7929
server.use(
8030
http.get(`${API_BASE_URL}/v1/companies/:company_id/payrolls`, () => {
8131
return HttpResponse.json(mockPayrollData)
@@ -227,13 +177,8 @@ describe('PayrollHistory', () => {
227177
})
228178

229179
it('shows cancel option only for cancellable payrolls', async () => {
230-
// Mock payroll data with unprocessed status to show cancel option
231-
const mockUnprocessedPayroll = [
232-
{
233-
...mockPayrollData[0],
234-
processed: false, // Unprocessed payroll should be cancellable
235-
},
236-
]
180+
// Use fixture with unprocessed payroll data
181+
const mockUnprocessedPayroll = await getFixture('payroll-history-unprocessed-test-data')
237182

238183
server.use(
239184
http.get(`${API_BASE_URL}/v1/companies/:company_id/payrolls`, () => {
@@ -257,13 +202,8 @@ describe('PayrollHistory', () => {
257202
})
258203

259204
it('handles payroll cancellation', async () => {
260-
// Mock unprocessed payroll
261-
const mockUnprocessedPayroll = [
262-
{
263-
...mockPayrollData[0],
264-
processed: false,
265-
},
266-
]
205+
// Use fixture with unprocessed payroll data
206+
const mockUnprocessedPayroll = await getFixture('payroll-history-unprocessed-test-data')
267207

268208
server.use(
269209
http.get(`${API_BASE_URL}/v1/companies/:company_id/payrolls`, () => {
@@ -303,12 +243,7 @@ describe('PayrollHistory', () => {
303243
})
304244

305245
it('handles cancellation errors gracefully', async () => {
306-
const mockUnprocessedPayroll = [
307-
{
308-
...mockPayrollData[0],
309-
processed: false,
310-
},
311-
]
246+
const mockUnprocessedPayroll = await getFixture('payroll-history-unprocessed-test-data')
312247

313248
server.use(
314249
http.get(`${API_BASE_URL}/v1/companies/:company_id/payrolls`, () => {

src/components/Payroll/PayrollHistory/PayrollHistory.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface PayrollHistoryItem {
3131
payDate: string
3232
status: PayrollHistoryStatus
3333
amount?: number
34+
payroll: Payroll
3435
}
3536

3637
export interface PayrollHistoryProps extends BaseComponentInterface<'Payroll.PayrollHistory'> {
@@ -112,6 +113,7 @@ const mapPayrollToHistoryItem = (payroll: Payroll, locale: string): PayrollHisto
112113
payDate: formatPayDate(payroll.checkDate),
113114
status: getPayrollStatus(payroll),
114115
amount: payroll.totals?.netPay ? Number(payroll.totals.netPay) : undefined,
116+
payroll,
115117
}
116118
}
117119

src/components/Payroll/PayrollHistory/PayrollHistoryPresentation.tsx

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,59 @@ export const PayrollHistoryPresentation = ({
5454
{ value: 'year', label: t('timeFilter.options.year') },
5555
]
5656

57-
const canCancelPayroll = (status: PayrollHistoryStatus) => {
58-
return status === 'Unprocessed' || status === 'Submitted' || status === 'In progress'
57+
const canCancelPayroll = (item: PayrollHistoryItem) => {
58+
const { status, payroll } = item
59+
60+
// Basic status check
61+
const hasValidStatus =
62+
status === 'Unprocessed' || status === 'Submitted' || status === 'In progress'
63+
if (!hasValidStatus) return false
64+
65+
// Check if payroll has cancellable flag set to false
66+
if (payroll.payrollStatusMeta?.cancellable === false) {
67+
return false
68+
}
69+
70+
// If payroll is processed, check the 3:30 PM PT deadline constraint
71+
if (payroll.processed && payroll.payrollDeadline) {
72+
const now = new Date()
73+
const deadline = new Date(payroll.payrollDeadline)
74+
75+
// Convert current time to PT (UTC-8 or UTC-7 depending on DST)
76+
const ptOffset = getPacificTimeOffset(now)
77+
const nowInPT = new Date(now.getTime() + ptOffset * 60 * 60 * 1000)
78+
const deadlineInPT = new Date(
79+
deadline.getTime() + getPacificTimeOffset(deadline) * 60 * 60 * 1000,
80+
)
81+
82+
// Check if it's the same day as deadline and after 3:30 PM PT
83+
const isSameDay = nowInPT.toDateString() === deadlineInPT.toDateString()
84+
if (isSameDay) {
85+
const cutoffTime = new Date(deadlineInPT)
86+
cutoffTime.setHours(15, 30, 0, 0) // 3:30 PM PT
87+
88+
if (nowInPT > cutoffTime) {
89+
return false
90+
}
91+
}
92+
}
93+
94+
return true
95+
}
96+
97+
const getPacificTimeOffset = (date: Date): number => {
98+
const year = date.getFullYear()
99+
100+
// Find second Sunday in March
101+
const secondSundayMarch = new Date(year, 2, 1)
102+
secondSundayMarch.setDate(1 + (7 - secondSundayMarch.getDay()) + 7)
103+
104+
// Find first Sunday in November
105+
const firstSundayNovember = new Date(year, 10, 1)
106+
firstSundayNovember.setDate(1 + ((7 - firstSundayNovember.getDay()) % 7))
107+
108+
const isDST = date >= secondSundayMarch && date < firstSundayNovember
109+
return isDST ? -7 : -8 // UTC-7 during DST, UTC-8 during standard time
59110
}
60111

61112
const getMenuItems = (item: PayrollHistoryItem) => {
@@ -76,7 +127,7 @@ export const PayrollHistoryPresentation = ({
76127
},
77128
]
78129

79-
if (canCancelPayroll(item.status)) {
130+
if (canCancelPayroll(item)) {
80131
items.push({
81132
label: t('menu.cancelPayroll'),
82133
icon: <TrashcanIcon aria-hidden />,
@@ -110,7 +161,9 @@ export const PayrollHistoryPresentation = ({
110161
<div className={styles.timeFilterContainer}>
111162
<Select
112163
value={selectedTimeFilter}
113-
onChange={onTimeFilterChange as (value: string) => void}
164+
onChange={(value: string) => {
165+
onTimeFilterChange(value as TimeFilterOption)
166+
}}
114167
options={timeFilterOptions}
115168
label={t('timeFilter.placeholder')}
116169
shouldVisuallyHideLabel
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
[
2+
{
3+
"payroll_uuid": "payroll-1",
4+
"processed": true,
5+
"check_date": "2024-12-15",
6+
"external": false,
7+
"off_cycle": false,
8+
"payroll_deadline": "2024-12-14T23:30:00Z",
9+
"payroll_status_meta": {
10+
"cancellable": false,
11+
"expected_check_date": "2024-12-15",
12+
"initial_check_date": "2024-12-15",
13+
"expected_debit_time": "2024-12-14T23:30:00Z",
14+
"payroll_late": false,
15+
"initial_debit_cutoff_time": "2024-12-14T23:30:00Z"
16+
},
17+
"pay_period": {
18+
"start_date": "2024-12-01",
19+
"end_date": "2024-12-15",
20+
"pay_schedule_uuid": "schedule-1"
21+
},
22+
"totals": {
23+
"net_pay": "2500.00",
24+
"gross_pay": "3200.00"
25+
}
26+
},
27+
{
28+
"payroll_uuid": "payroll-2",
29+
"processed": true,
30+
"check_date": "2024-11-30",
31+
"external": false,
32+
"off_cycle": true,
33+
"payroll_deadline": "2024-11-29T23:30:00Z",
34+
"payroll_status_meta": {
35+
"cancellable": false,
36+
"expected_check_date": "2024-11-30",
37+
"initial_check_date": "2024-11-30",
38+
"expected_debit_time": "2024-11-29T23:30:00Z",
39+
"payroll_late": false,
40+
"initial_debit_cutoff_time": "2024-11-29T23:30:00Z"
41+
},
42+
"pay_period": {
43+
"start_date": "2024-11-15",
44+
"end_date": "2024-11-30",
45+
"pay_schedule_uuid": "schedule-1"
46+
},
47+
"totals": {
48+
"net_pay": "1800.00",
49+
"gross_pay": "2300.00"
50+
}
51+
},
52+
{
53+
"payroll_uuid": "payroll-3",
54+
"processed": true,
55+
"check_date": "2024-11-15",
56+
"external": true,
57+
"off_cycle": false,
58+
"payroll_deadline": "2024-11-14T23:30:00Z",
59+
"payroll_status_meta": {
60+
"cancellable": false,
61+
"expected_check_date": "2024-11-15",
62+
"initial_check_date": "2024-11-15",
63+
"expected_debit_time": "2024-11-14T23:30:00Z",
64+
"payroll_late": false,
65+
"initial_debit_cutoff_time": "2024-11-14T23:30:00Z"
66+
},
67+
"pay_period": {
68+
"start_date": "2024-11-01",
69+
"end_date": "2024-11-15",
70+
"pay_schedule_uuid": "schedule-1"
71+
},
72+
"totals": {
73+
"net_pay": "3000.00",
74+
"gross_pay": "3850.00"
75+
}
76+
}
77+
]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[
2+
{
3+
"payroll_uuid": "payroll-1",
4+
"processed": false,
5+
"check_date": "2024-12-15",
6+
"external": false,
7+
"off_cycle": false,
8+
"payroll_deadline": "2024-12-14T23:30:00Z",
9+
"payroll_status_meta": {
10+
"cancellable": true,
11+
"expected_check_date": "2024-12-15",
12+
"initial_check_date": "2024-12-15",
13+
"expected_debit_time": "2024-12-14T23:30:00Z",
14+
"payroll_late": false,
15+
"initial_debit_cutoff_time": "2024-12-14T23:30:00Z"
16+
},
17+
"pay_period": {
18+
"start_date": "2024-12-01",
19+
"end_date": "2024-12-15",
20+
"pay_schedule_uuid": "schedule-1"
21+
},
22+
"totals": {
23+
"net_pay": "2500.00",
24+
"gross_pay": "3200.00"
25+
}
26+
}
27+
]

0 commit comments

Comments
 (0)