@servicetitan/navigation 8.1.7 → 8.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/header-navigation/header-navigation-links.d.ts.map +1 -1
- package/dist/components/header-navigation/header-navigation-links.js +1 -1
- package/dist/components/header-navigation/header-navigation-links.js.map +1 -1
- package/dist/components/layout.stories.d.ts +1 -0
- package/dist/components/layout.stories.d.ts.map +1 -1
- package/dist/components/layout.stories.js +6 -2
- package/dist/components/layout.stories.js.map +1 -1
- package/dist/components/left-navigation/header-navigation-tiny.stories.js +1 -1
- package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
- package/dist/components/left-navigation/side-navigation.d.ts.map +1 -1
- package/dist/components/left-navigation/side-navigation.js +40 -5
- package/dist/components/left-navigation/side-navigation.js.map +1 -1
- package/dist/components/left-navigation/side-navigation.module.less +119 -2
- package/dist/components/left-navigation/side-navigation.stories.d.ts +1 -0
- package/dist/components/left-navigation/side-navigation.stories.d.ts.map +1 -1
- package/dist/components/left-navigation/side-navigation.stories.js +19 -2
- package/dist/components/left-navigation/side-navigation.stories.js.map +1 -1
- package/dist/test/data.d.ts +4 -0
- package/dist/test/data.d.ts.map +1 -1
- package/dist/test/data.js +83 -7
- package/dist/test/data.js.map +1 -1
- package/dist/utils/navigation.d.ts +23 -9
- package/dist/utils/navigation.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/header-navigation/header-navigation-links.tsx +2 -0
- package/src/components/layout.stories.tsx +19 -1
- package/src/components/left-navigation/header-navigation-tiny.stories.tsx +1 -1
- package/src/components/left-navigation/side-navigation.module.less +119 -2
- package/src/components/left-navigation/side-navigation.module.less.d.ts +7 -0
- package/src/components/left-navigation/side-navigation.stories.tsx +33 -2
- package/src/components/left-navigation/side-navigation.tsx +173 -13
- package/src/test/data.tsx +99 -8
- package/src/utils/navigation.ts +31 -13
package/src/test/data.tsx
CHANGED
|
@@ -30,7 +30,7 @@ import SvgSchedule from '@servicetitan/anvil2/assets/icons/st/gnav_schedule_inac
|
|
|
30
30
|
import SvgTasksActive from '@servicetitan/anvil2/assets/icons/st/gnav_tasks_active.svg';
|
|
31
31
|
import SvgTasks from '@servicetitan/anvil2/assets/icons/st/gnav_tasks_inactive.svg';
|
|
32
32
|
|
|
33
|
-
import { Popover } from '@servicetitan/design-system';
|
|
33
|
+
import { BodyText, Popover } from '@servicetitan/design-system';
|
|
34
34
|
|
|
35
35
|
import classNames from 'classnames';
|
|
36
36
|
import { forwardRef, useState } from 'react';
|
|
@@ -38,7 +38,12 @@ import { forwardRef, useState } from 'react';
|
|
|
38
38
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
39
39
|
import { MemoryRouter, useHistory, useLocation } from 'react-router-dom';
|
|
40
40
|
import { HeaderNavigationTrigger } from '../components/links';
|
|
41
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
HeaderNavigationItemData,
|
|
43
|
+
HeaderNavigationItemLinkProps,
|
|
44
|
+
HeaderNavigationItemSubmenuGroup,
|
|
45
|
+
NavLinkComponentProps,
|
|
46
|
+
} from '../utils/navigation';
|
|
42
47
|
import { NavigationComponentContext } from '../utils/navigation-context';
|
|
43
48
|
import * as Styles from './data-stories.module.less';
|
|
44
49
|
|
|
@@ -46,20 +51,21 @@ export const NavLinkMock = forwardRef<any, NavLinkComponentProps>(
|
|
|
46
51
|
({ to, children, activeClassName, className, isActive, ...rest }, ref) => {
|
|
47
52
|
const history = useHistory();
|
|
48
53
|
const location = useLocation();
|
|
49
|
-
const linkActive = location.pathname.
|
|
54
|
+
const linkActive = location.pathname.startsWith(to);
|
|
50
55
|
|
|
51
56
|
return (
|
|
52
57
|
<a
|
|
53
58
|
{...rest}
|
|
54
|
-
className={classNames(className, linkActive ? activeClassName : '')}
|
|
55
|
-
href={to}
|
|
56
59
|
onClick={e => {
|
|
57
60
|
e.preventDefault();
|
|
61
|
+
e.stopPropagation();
|
|
58
62
|
|
|
59
63
|
if (!to.startsWith('http')) {
|
|
60
|
-
history.
|
|
64
|
+
history.replace(to);
|
|
61
65
|
}
|
|
62
66
|
}}
|
|
67
|
+
className={classNames(className, linkActive ? activeClassName : '')}
|
|
68
|
+
href={to}
|
|
63
69
|
ref={ref}
|
|
64
70
|
>
|
|
65
71
|
{children}
|
|
@@ -68,6 +74,12 @@ export const NavLinkMock = forwardRef<any, NavLinkComponentProps>(
|
|
|
68
74
|
}
|
|
69
75
|
);
|
|
70
76
|
|
|
77
|
+
export const LocationInfo = () => {
|
|
78
|
+
const location = useLocation();
|
|
79
|
+
|
|
80
|
+
return <BodyText>current location - {location.pathname}</BodyText>;
|
|
81
|
+
};
|
|
82
|
+
|
|
71
83
|
export const withMemoryRouter = (Story: any) => (
|
|
72
84
|
<MemoryRouter>
|
|
73
85
|
<NavigationComponentContext.Provider value={NavLinkMock}>
|
|
@@ -111,12 +123,42 @@ const getItem = (
|
|
|
111
123
|
data: Partial<HeaderNavigationItemData>
|
|
112
124
|
): HeaderNavigationItemData => ({
|
|
113
125
|
id,
|
|
114
|
-
to: id,
|
|
126
|
+
to: '/' + id,
|
|
115
127
|
title: id[0].toUpperCase() + id.substring(1),
|
|
116
128
|
hint: id,
|
|
117
129
|
icon: undefined,
|
|
118
130
|
iconActive: undefined,
|
|
119
131
|
...(data ?? {}),
|
|
132
|
+
submenu: data.submenu
|
|
133
|
+
? {
|
|
134
|
+
...data.submenu,
|
|
135
|
+
groups: data.submenu.groups.map(group => ({
|
|
136
|
+
...group,
|
|
137
|
+
links: group.links.map(link => ({
|
|
138
|
+
...link,
|
|
139
|
+
to: `/${id}/${link.to}`,
|
|
140
|
+
})),
|
|
141
|
+
})),
|
|
142
|
+
}
|
|
143
|
+
: undefined,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const getSubItem = (
|
|
147
|
+
id: string,
|
|
148
|
+
data: Partial<HeaderNavigationItemLinkProps>
|
|
149
|
+
): HeaderNavigationItemLinkProps => ({
|
|
150
|
+
id,
|
|
151
|
+
to: id,
|
|
152
|
+
title: id[0].toUpperCase() + id.substring(1),
|
|
153
|
+
...(data ?? {}),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const getGroup = (
|
|
157
|
+
title: string,
|
|
158
|
+
links: HeaderNavigationItemLinkProps[]
|
|
159
|
+
): HeaderNavigationItemSubmenuGroup => ({
|
|
160
|
+
title,
|
|
161
|
+
links,
|
|
120
162
|
});
|
|
121
163
|
|
|
122
164
|
export const items = {
|
|
@@ -159,23 +201,72 @@ export const items = {
|
|
|
159
201
|
iconActive: SvgFollowUpActive,
|
|
160
202
|
title: 'Follow Up',
|
|
161
203
|
}),
|
|
204
|
+
followUpsWithSubmenu: getItem('followUps', {
|
|
205
|
+
iconName: 'flag',
|
|
206
|
+
icon: SvgFollowUp,
|
|
207
|
+
iconActive: SvgFollowUpActive,
|
|
208
|
+
title: 'Follow Up',
|
|
209
|
+
submenu: {
|
|
210
|
+
groups: [
|
|
211
|
+
getGroup('', [
|
|
212
|
+
getSubItem('estimates', { title: 'Unsold Estimates' }),
|
|
213
|
+
getSubItem('sold', { title: 'Sold Estimates' }),
|
|
214
|
+
getSubItem('surveys', { title: 'Surveys' }),
|
|
215
|
+
]),
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
}),
|
|
162
219
|
inventory: getItem('inventory', {
|
|
163
220
|
iconName: 'toys',
|
|
164
221
|
icon: SvgInventory,
|
|
165
222
|
iconActive: SvgInventoryActive,
|
|
166
223
|
}),
|
|
167
224
|
purchasing: getItem('purchasing', { iconComponent: InventoryIcon }),
|
|
225
|
+
purchasingWithSubmenu: getItem('purchasing', {
|
|
226
|
+
iconName: 'toys',
|
|
227
|
+
icon: SvgInventory,
|
|
228
|
+
iconActive: SvgInventoryActive,
|
|
229
|
+
submenu: {
|
|
230
|
+
groups: [
|
|
231
|
+
getGroup('Purchase', [
|
|
232
|
+
getSubItem('repl', { title: 'Replenishment' }),
|
|
233
|
+
getSubItem('orders', { title: 'Purchase Orders' }),
|
|
234
|
+
getSubItem('receipts', { title: 'Receipts' }),
|
|
235
|
+
getSubItem('returns', { title: 'Returns' }),
|
|
236
|
+
]),
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
}),
|
|
168
240
|
accounting: getItem('accounting', {
|
|
169
241
|
iconName: 'assignment',
|
|
170
242
|
icon: SvgAccounting,
|
|
171
243
|
iconActive: SvgAccountingActive,
|
|
172
244
|
}),
|
|
245
|
+
accountingWithSubmenu: getItem('accounting', {
|
|
246
|
+
iconName: 'assignment',
|
|
247
|
+
icon: SvgAccounting,
|
|
248
|
+
iconActive: SvgAccountingActive,
|
|
249
|
+
submenu: {
|
|
250
|
+
groups: [
|
|
251
|
+
getGroup('Accounts Receivable', [
|
|
252
|
+
getSubItem('ar', { title: 'AR Management' }),
|
|
253
|
+
getSubItem('export', { title: 'Batch/Export Transactions' }),
|
|
254
|
+
getSubItem('invoices', { title: 'Invoices' }),
|
|
255
|
+
getSubItem('payments', { title: 'Customer Payments' }),
|
|
256
|
+
getSubItem('deposits', { title: 'Bank Deposits' }),
|
|
257
|
+
]),
|
|
258
|
+
getGroup('Accounts Payable', [getSubItem('bills', { title: 'Bills' })]),
|
|
259
|
+
getGroup('Financing', [getSubItem('dashboard', { title: 'Dashboard' })]),
|
|
260
|
+
getGroup('Others', [getSubItem('at', { title: 'Accounting Audit Trail' })]),
|
|
261
|
+
],
|
|
262
|
+
},
|
|
263
|
+
}),
|
|
173
264
|
marketing: getItem('marketing', {
|
|
174
265
|
iconName: 'bullhorn',
|
|
175
266
|
icon: SvgMarketing,
|
|
176
267
|
iconActive: SvgMarketingActive,
|
|
177
268
|
}),
|
|
178
|
-
priceBook: getItem('
|
|
269
|
+
priceBook: getItem('pricebook', {
|
|
179
270
|
iconName: 'book',
|
|
180
271
|
icon: SvgPriceBook,
|
|
181
272
|
iconActive: SvgPriceBookActive,
|
package/src/utils/navigation.ts
CHANGED
|
@@ -3,22 +3,10 @@ import { IconPropsStrict } from '@servicetitan/design-system';
|
|
|
3
3
|
import { FC, HTMLAttributeAnchorTarget, ReactNode } from 'react';
|
|
4
4
|
import { CounterTagPropsType } from '../components/counter-tag';
|
|
5
5
|
|
|
6
|
-
export interface HeaderNavigationItemData {
|
|
7
|
-
/** link id */
|
|
8
|
-
id: string;
|
|
9
|
-
|
|
10
|
-
/** link href */
|
|
11
|
-
to: string;
|
|
12
|
-
|
|
13
|
-
/** link title */
|
|
14
|
-
title: string;
|
|
15
|
-
|
|
6
|
+
export interface HeaderNavigationItemData extends HeaderNavigationItemLinkProps {
|
|
16
7
|
/** link description */
|
|
17
8
|
hint: string;
|
|
18
9
|
|
|
19
|
-
/** callback to return active state. By default, it compares link href with current pathname */
|
|
20
|
-
isActive?: boolean | ((pathname: string) => boolean);
|
|
21
|
-
|
|
22
10
|
/** flag if the link is not shown (based on FG and/or user permissions) */
|
|
23
11
|
isHidden?: boolean;
|
|
24
12
|
|
|
@@ -42,6 +30,36 @@ export interface HeaderNavigationItemData {
|
|
|
42
30
|
|
|
43
31
|
/** class name of link item */
|
|
44
32
|
className?: string;
|
|
33
|
+
|
|
34
|
+
/** optional submenu of link item */
|
|
35
|
+
submenu?: HeaderNavigationItemSubmenu;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface HeaderNavigationItemLinkProps {
|
|
39
|
+
/** link id */
|
|
40
|
+
id: string;
|
|
41
|
+
|
|
42
|
+
/** link href */
|
|
43
|
+
to: string;
|
|
44
|
+
|
|
45
|
+
/** link title */
|
|
46
|
+
title: string;
|
|
47
|
+
|
|
48
|
+
/** callback to return active state. By default, it compares link href with current pathname */
|
|
49
|
+
isActive?: boolean | ((pathname: string) => boolean);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface HeaderNavigationItemSubmenu {
|
|
53
|
+
/** submenu groups */
|
|
54
|
+
groups: HeaderNavigationItemSubmenuGroup[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface HeaderNavigationItemSubmenuGroup {
|
|
58
|
+
/** submenu group title */
|
|
59
|
+
title: string;
|
|
60
|
+
|
|
61
|
+
/** submenu group links */
|
|
62
|
+
links: HeaderNavigationItemLinkProps[];
|
|
45
63
|
}
|
|
46
64
|
|
|
47
65
|
export interface NavLinkComponentPropsStrict {
|