Skip to content

Commit 1e3b6a2

Browse files
sf-madhuri-uppusf-deepali-bharmalsf-emmyzhang
authored
@W-18998088 Order tracker on order details page (#2790)
* Initial empty commit for order-management-plugin * skip changelog * add white border to svg * skip changelog * order tracker * Fixed lint errors * Addressed PR comments * Removed unnecessary comments * Refactored the code * Made the tracker accessible * PR comments * Added compiled files --------- Co-authored-by: sf-deepali-bharmal <deepali.bharmal@salesforce.com> Co-authored-by: emmyzhang <emmyzhang@salesforce.com>
1 parent 91aa36d commit 1e3b6a2

File tree

10 files changed

+810
-0
lines changed

10 files changed

+810
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import React from 'react'
8+
import {useTheme} from '@chakra-ui/react'
9+
import PropTypes from 'prop-types'
10+
import {useIntl} from 'react-intl'
11+
import StatusBar from '@salesforce/retail-react-app/app/components/order-status-bar/status-bar'
12+
13+
const steps = ['Ordered', 'Dispatched', 'Out for delivery', 'Delivered']
14+
15+
const OrderStatusBar = ({currentStepLabel}) => {
16+
const theme = useTheme()
17+
const intl = useIntl()
18+
19+
const getLocalizedMessage = (status) => {
20+
switch (status) {
21+
case 'Ordered':
22+
return intl.formatMessage({id: 'status_bar.ordered', defaultMessage: 'Ordered'})
23+
case 'Dispatched':
24+
return intl.formatMessage({
25+
id: 'status_bar.dispatched',
26+
defaultMessage: 'Dispatched'
27+
})
28+
case 'Out for delivery':
29+
return intl.formatMessage({
30+
id: 'status_bar.out_for_delivery',
31+
defaultMessage: 'Out for delivery'
32+
})
33+
case 'Delivered':
34+
return intl.formatMessage({id: 'status_bar.delivered', defaultMessage: 'Delivered'})
35+
default:
36+
return status
37+
}
38+
}
39+
40+
// Convert steps to the format expected by StatusBar component
41+
const statusBarSteps = steps.map((step) => ({
42+
label: getLocalizedMessage(step),
43+
status: step,
44+
description: `Order status: ${getLocalizedMessage(step)}`
45+
}))
46+
47+
// Find current step index
48+
let currentStep = steps.findIndex((step) => step === currentStepLabel)
49+
if (currentStep === -1) currentStep = 0
50+
51+
// Define colors using theme
52+
const colors = {
53+
completed: theme.colors.teal[100], // completed steps
54+
current: theme.colors.blue[900], // current step
55+
future: theme.colors.gray[200], // future steps
56+
completedText: theme.colors.black[600], // completed steps text
57+
currentText: 'white', // current step text
58+
futureText: theme.colors.black[600] // future steps text
59+
}
60+
61+
return (
62+
<StatusBar
63+
steps={statusBarSteps}
64+
currentStep={currentStep}
65+
colors={colors}
66+
ariaLabel="Order Status Steps"
67+
width={1080}
68+
height={50}
69+
chevronWidth={24}
70+
radius={25}
71+
/>
72+
)
73+
}
74+
75+
OrderStatusBar.propTypes = {
76+
currentStepLabel: PropTypes.string
77+
}
78+
79+
export default OrderStatusBar
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import React from 'react'
8+
import {screen} from '@testing-library/react'
9+
import {renderWithProviders} from '@salesforce/retail-react-app/app/utils/test-utils'
10+
import OrderStatusBar from '.'
11+
12+
describe('OrderStatusBar', () => {
13+
beforeEach(() => jest.clearAllMocks())
14+
15+
test('renders all step labels with localized messages', () => {
16+
renderWithProviders(<OrderStatusBar />)
17+
18+
expect(screen.getByText('Ordered')).toBeInTheDocument()
19+
expect(screen.getByText('Dispatched')).toBeInTheDocument()
20+
expect(screen.getByText('Out for delivery')).toBeInTheDocument()
21+
expect(screen.getByText('Delivered')).toBeInTheDocument()
22+
})
23+
24+
test('renders step labels with responsive font sizes and word wrapping', () => {
25+
renderWithProviders(<OrderStatusBar />)
26+
27+
const labels = screen.getAllByText(/Ordered|Dispatched|Out for delivery|Delivered/)
28+
labels.forEach((label) => {
29+
// Check that the component renders without errors
30+
expect(label).toBeInTheDocument()
31+
})
32+
})
33+
34+
test('renders SVG element with correct attributes', () => {
35+
renderWithProviders(<OrderStatusBar />)
36+
37+
const svg = document.querySelector('svg')
38+
expect(svg).toBeInTheDocument()
39+
expect(svg).toHaveAttribute('viewBox', '0 0 1080 50')
40+
expect(svg).toHaveAttribute('width', '100%')
41+
expect(svg).toHaveAttribute('preserveAspectRatio', 'none')
42+
expect(svg).toHaveStyle({display: 'block'})
43+
})
44+
45+
test('renders all step paths in SVG with correct count', () => {
46+
renderWithProviders(<OrderStatusBar />)
47+
48+
const svg = document.querySelector('svg')
49+
const paths = svg.querySelectorAll('path')
50+
expect(paths).toHaveLength(4) // Should have 4 paths for 4 steps
51+
})
52+
53+
test('renders with different currentStepLabel props and updates colors accordingly', () => {
54+
const {rerender} = renderWithProviders(<OrderStatusBar currentStepLabel="Ordered" />)
55+
expect(screen.getByText('Ordered')).toBeInTheDocument()
56+
57+
rerender(<OrderStatusBar currentStepLabel="Dispatched" />)
58+
expect(screen.getByText('Dispatched')).toBeInTheDocument()
59+
60+
rerender(<OrderStatusBar currentStepLabel="Delivered" />)
61+
expect(screen.getByText('Delivered')).toBeInTheDocument()
62+
63+
rerender(<OrderStatusBar currentStepLabel="Invalid Step" />)
64+
expect(screen.getByText('Ordered')).toBeInTheDocument()
65+
66+
rerender(<OrderStatusBar currentStepLabel="" />)
67+
expect(screen.getByText('Ordered')).toBeInTheDocument()
68+
69+
rerender(<OrderStatusBar currentStepLabel={undefined} />)
70+
expect(screen.getByText('Ordered')).toBeInTheDocument()
71+
72+
rerender(<OrderStatusBar currentStepLabel={['Ordered', 'Dispatched']} />)
73+
expect(screen.getByText('Ordered')).toBeInTheDocument()
74+
})
75+
76+
test('renders container with correct positioning and dimensions', () => {
77+
renderWithProviders(<OrderStatusBar />)
78+
79+
// The container is a Chakra UI Box component, so we check for the SVG instead
80+
const svg = document.querySelector('svg')
81+
expect(svg).toBeInTheDocument()
82+
expect(svg).toHaveAttribute('width', '100%')
83+
expect(svg).toHaveAttribute('viewBox', '0 0 1080 50')
84+
})
85+
86+
test('renders text labels with correct styling properties', () => {
87+
renderWithProviders(<OrderStatusBar />)
88+
89+
const labels = screen.getAllByText(/Ordered|Dispatched|Out for delivery|Delivered/)
90+
labels.forEach((label) => {
91+
// Check that labels are rendered
92+
expect(label).toBeInTheDocument()
93+
})
94+
})
95+
96+
test('handles case-sensitive step label matching', () => {
97+
// Test case-insensitive matching
98+
const {rerender} = renderWithProviders(<OrderStatusBar currentStepLabel="ordered" />)
99+
expect(screen.getByText('Ordered')).toBeInTheDocument()
100+
101+
// Test with different case
102+
rerender(<OrderStatusBar currentStepLabel="DISPATCHED" />)
103+
expect(screen.getByText('Dispatched')).toBeInTheDocument()
104+
105+
// Test with mixed case
106+
rerender(<OrderStatusBar currentStepLabel="Out For Delivery" />)
107+
expect(screen.getByText('Out for delivery')).toBeInTheDocument()
108+
})
109+
})

0 commit comments

Comments
 (0)