@brownandroot/api 1.0.0 → 1.2.0
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/README.md +346 -152
- package/dist/businessUnits.remote.d.ts +3 -4
- package/dist/businessUnits.remote.js +0 -1
- package/dist/cache.d.ts +152 -0
- package/dist/cache.js +324 -0
- package/dist/costcodes.remote.d.ts +3 -6
- package/dist/costcodes.remote.js +0 -7
- package/dist/employees.remote.d.ts +15 -10
- package/dist/employees.remote.js +1 -4
- package/dist/idb.d.ts +13 -0
- package/dist/idb.js +79 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +4 -0
- package/dist/jobtypejobsteps.remote.d.ts +3 -3
- package/dist/llm.remote.d.ts +12 -2
- package/dist/paytypes.remote.d.ts +3 -4
- package/dist/paytypes.remote.js +0 -1
- package/dist/rag.remote.d.ts +11 -4
- package/dist/workorders.remote.d.ts +3 -5
- package/dist/workorders.remote.js +0 -2
- package/package.json +5 -1
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side cache API for @brownandroot/api.
|
|
3
|
+
*
|
|
4
|
+
* Wraps remote functions with an IndexedDB stale-while-revalidate cache so
|
|
5
|
+
* pages load instantly on subsequent visits. Filters are applied in-memory
|
|
6
|
+
* against the full cached dataset — no per-field server endpoints needed.
|
|
7
|
+
*
|
|
8
|
+
* Import from: @brownandroot/api/cache
|
|
9
|
+
*/
|
|
10
|
+
import type { Employee, EmployeePrivileged, BusinessUnit, Costcode, Paytype, Workorder, Jobtypejobstep, DropdownOption, PaytypeDropdownOption } from './index.js';
|
|
11
|
+
import { type IdbStore } from './idb.js';
|
|
12
|
+
export interface EmployeeFilters {
|
|
13
|
+
/** Exact match on businessUnitId */
|
|
14
|
+
businessUnitId?: string;
|
|
15
|
+
/** Exact match on home business unit (hbu) */
|
|
16
|
+
hbu?: string;
|
|
17
|
+
/** Exact match on supervisor employee ID */
|
|
18
|
+
supervisor?: string;
|
|
19
|
+
/** Exact match on payClass */
|
|
20
|
+
payClass?: string;
|
|
21
|
+
/** Exact match on jobType */
|
|
22
|
+
jobType?: string;
|
|
23
|
+
/** Exact match on jobStep */
|
|
24
|
+
jobStep?: string;
|
|
25
|
+
/** Exact match on sector */
|
|
26
|
+
sector?: string;
|
|
27
|
+
/** Exact match on division */
|
|
28
|
+
division?: string;
|
|
29
|
+
/** Case-insensitive partial match on name or email */
|
|
30
|
+
q?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface WorkorderFilters {
|
|
33
|
+
/** Exact match on businessUnitId */
|
|
34
|
+
businessUnitId?: string;
|
|
35
|
+
/** Exact match on costCodeId */
|
|
36
|
+
costCodeId?: string;
|
|
37
|
+
/** Exact match on isActive */
|
|
38
|
+
isActive?: boolean;
|
|
39
|
+
/** Exact match on completed */
|
|
40
|
+
completed?: boolean;
|
|
41
|
+
/** Exact match on area */
|
|
42
|
+
area?: string;
|
|
43
|
+
/** Exact match on parentWorkOrder */
|
|
44
|
+
parentWorkOrder?: string;
|
|
45
|
+
/** Case-insensitive partial match on description or clientWorkOrderId */
|
|
46
|
+
q?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface CostcodeFilters {
|
|
49
|
+
/** Exact match on businessUnitId */
|
|
50
|
+
businessUnitId?: string;
|
|
51
|
+
/** Exact match on isActive */
|
|
52
|
+
isActive?: boolean;
|
|
53
|
+
/** Exact match on entryFlag */
|
|
54
|
+
entryFlag?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Filter by pay type — resolves the pay type's objectAccount and returns
|
|
57
|
+
* only cost codes whose objectAccount matches. If the pay type has no
|
|
58
|
+
* objectAccount, all cost codes pass this filter.
|
|
59
|
+
*/
|
|
60
|
+
payTypeCode?: string;
|
|
61
|
+
/** Case-insensitive partial match on description or jdeCostCode */
|
|
62
|
+
q?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface PaytypeFilters {
|
|
65
|
+
/** Exact match on payClass */
|
|
66
|
+
payClass?: string;
|
|
67
|
+
/** Exact match on category */
|
|
68
|
+
category?: string;
|
|
69
|
+
/** Exact match on type */
|
|
70
|
+
type?: string;
|
|
71
|
+
/** Exact match on isActive */
|
|
72
|
+
isActive?: boolean;
|
|
73
|
+
/** Exact match on perDiemPayType */
|
|
74
|
+
perDiemPayType?: boolean;
|
|
75
|
+
/** Case-insensitive partial match on description */
|
|
76
|
+
q?: string;
|
|
77
|
+
}
|
|
78
|
+
export interface BusinessUnitFilters {
|
|
79
|
+
/** Exact match on subsector */
|
|
80
|
+
subsector?: string;
|
|
81
|
+
/** Exact match on isActive */
|
|
82
|
+
isActive?: boolean;
|
|
83
|
+
/** Exact match on clientId */
|
|
84
|
+
clientId?: string;
|
|
85
|
+
/** Case-insensitive partial match on description or clientDescription */
|
|
86
|
+
q?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface JobtypejobstepFilters {
|
|
89
|
+
/** Exact match on jobType */
|
|
90
|
+
jobType?: string;
|
|
91
|
+
/** Exact match on payclass */
|
|
92
|
+
payclass?: string;
|
|
93
|
+
/** Exact match on isActive */
|
|
94
|
+
isActive?: boolean;
|
|
95
|
+
/** Exact match on grp */
|
|
96
|
+
grp?: string;
|
|
97
|
+
/** Case-insensitive partial match on description, jobType, or jobStep */
|
|
98
|
+
q?: string;
|
|
99
|
+
}
|
|
100
|
+
export declare function getEmployees(filters?: EmployeeFilters): Promise<Employee[]>;
|
|
101
|
+
export declare function getEmployeesDropdown(filters?: EmployeeFilters): Promise<DropdownOption[]>;
|
|
102
|
+
/** Single employee by ID — always fetches fresh (no IndexedDB). */
|
|
103
|
+
export declare function getEmployee(employeeId: string): Promise<Employee>;
|
|
104
|
+
/** Single employee by ID including compensation fields — always fetches fresh (no IndexedDB). */
|
|
105
|
+
export declare function getEmployeePrivileged(employeeId: string): Promise<EmployeePrivileged>;
|
|
106
|
+
/** Full supervisor chain above an employee — always fetches fresh. */
|
|
107
|
+
export declare function getSupervisorChain(employeeId: string): Promise<Employee[]>;
|
|
108
|
+
/** Look up JDE number and employee from email — always fetches fresh. */
|
|
109
|
+
export declare function getJdeFromEmail(email: string): Promise<{
|
|
110
|
+
jde: string | null;
|
|
111
|
+
employee: Employee | null;
|
|
112
|
+
}>;
|
|
113
|
+
/** Verify employee identity — always fetches fresh. */
|
|
114
|
+
export declare function verifyIdentity(inputs: {
|
|
115
|
+
first3FirstName: string;
|
|
116
|
+
first3LastName: string;
|
|
117
|
+
dob: string;
|
|
118
|
+
ssn4: string;
|
|
119
|
+
}): Promise<Employee | null>;
|
|
120
|
+
export declare function getWorkorders(filters?: WorkorderFilters): Promise<Workorder[]>;
|
|
121
|
+
export declare function getWorkordersDropdown(filters?: WorkorderFilters): Promise<DropdownOption[]>;
|
|
122
|
+
/** Single workorder by ID — always fetches fresh (no IndexedDB). */
|
|
123
|
+
export declare function getWorkorder(id: string): Promise<Workorder>;
|
|
124
|
+
export declare function getCostcodes(filters?: CostcodeFilters): Promise<Costcode[]>;
|
|
125
|
+
export declare function getCostcodesDropdown(filters?: CostcodeFilters): Promise<DropdownOption[]>;
|
|
126
|
+
/** Single cost code by ID — always fetches fresh (no IndexedDB). */
|
|
127
|
+
export declare function getCostcode(id: string): Promise<Costcode>;
|
|
128
|
+
export declare function getPaytypes(filters?: PaytypeFilters): Promise<Paytype[]>;
|
|
129
|
+
export declare function getPaytypesDropdown(filters?: PaytypeFilters): Promise<PaytypeDropdownOption[]>;
|
|
130
|
+
/** Single pay type by ID — always fetches fresh (no IndexedDB). */
|
|
131
|
+
export declare function getPaytype(id: string): Promise<Paytype>;
|
|
132
|
+
export declare function getBusinessUnits(filters?: BusinessUnitFilters): Promise<BusinessUnit[]>;
|
|
133
|
+
export declare function getBusinessUnitsDropdown(filters?: BusinessUnitFilters): Promise<DropdownOption[]>;
|
|
134
|
+
/** Single business unit by ID — always fetches fresh (no IndexedDB). */
|
|
135
|
+
export declare function getBusinessUnit(id: string): Promise<BusinessUnit>;
|
|
136
|
+
export declare function getJobtypejobsteps(filters?: JobtypejobstepFilters): Promise<Jobtypejobstep[]>;
|
|
137
|
+
export declare function getJobtypejobstepsDropdown(filters?: JobtypejobstepFilters): Promise<DropdownOption[]>;
|
|
138
|
+
/** Single job type/job step by ID — always fetches fresh (no IndexedDB). */
|
|
139
|
+
export declare function getJobtypejobstep(id: string): Promise<Jobtypejobstep>;
|
|
140
|
+
/**
|
|
141
|
+
* Clear the IndexedDB cache for a specific entity, or all entities.
|
|
142
|
+
*
|
|
143
|
+
* Call after mutations to ensure the next read fetches fresh data from
|
|
144
|
+
* the server instead of returning stale cached results.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* await createWorkorder(data)
|
|
148
|
+
* clearCache('workorders') // next getWorkorders() will re-fetch
|
|
149
|
+
*
|
|
150
|
+
* clearCache() // clear everything
|
|
151
|
+
*/
|
|
152
|
+
export declare function clearCache(entity?: IdbStore): void;
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side cache API for @brownandroot/api.
|
|
3
|
+
*
|
|
4
|
+
* Wraps remote functions with an IndexedDB stale-while-revalidate cache so
|
|
5
|
+
* pages load instantly on subsequent visits. Filters are applied in-memory
|
|
6
|
+
* against the full cached dataset — no per-field server endpoints needed.
|
|
7
|
+
*
|
|
8
|
+
* Import from: @brownandroot/api/cache
|
|
9
|
+
*/
|
|
10
|
+
import { idbGet, idbSet, idbClear } from './idb.js';
|
|
11
|
+
// Remote functions — called as HTTP on the client, directly on the server (SSR)
|
|
12
|
+
import { getEmployees as _getEmployees, getEmployee as _getEmployee, getEmployeePrivileged as _getEmployeePrivileged, getJdeFromEmail as _getJdeFromEmail, getSupervisorChain as _getSupervisorChain, verifyIdentity as _verifyIdentity, } from './employees.remote.js';
|
|
13
|
+
import { getBusinessUnits as _getBusinessUnits, getBusinessUnit as _getBusinessUnit } from './businessUnits.remote.js';
|
|
14
|
+
import { getCostcodes as _getCostcodes, getCostcode as _getCostcode } from './costcodes.remote.js';
|
|
15
|
+
import { getPaytypes as _getPaytypes, getPaytype as _getPaytype } from './paytypes.remote.js';
|
|
16
|
+
import { getWorkorders as _getWorkorders, getWorkorder as _getWorkorder } from './workorders.remote.js';
|
|
17
|
+
import { getJobtypejobsteps as _getJobtypejobsteps, getJobtypejobstep as _getJobtypejobstep, } from './jobtypejobsteps.remote.js';
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Internal: stale-while-revalidate fetch helpers
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
async function loadCached(store, fetcher) {
|
|
22
|
+
const cached = await idbGet(store, 'all');
|
|
23
|
+
if (cached) {
|
|
24
|
+
// Return stale data immediately; refresh in background for next call
|
|
25
|
+
fetcher()
|
|
26
|
+
.then((fresh) => idbSet(store, 'all', fresh))
|
|
27
|
+
.catch(() => { });
|
|
28
|
+
return cached.data;
|
|
29
|
+
}
|
|
30
|
+
// Cache miss — must await
|
|
31
|
+
const data = await fetcher();
|
|
32
|
+
await idbSet(store, 'all', data);
|
|
33
|
+
return data;
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Internal: filter helpers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
function applyEmployeeFilters(data, f) {
|
|
39
|
+
if (!f)
|
|
40
|
+
return data;
|
|
41
|
+
return data.filter((e) => {
|
|
42
|
+
if (f.businessUnitId !== undefined && e.businessUnitId !== f.businessUnitId)
|
|
43
|
+
return false;
|
|
44
|
+
if (f.hbu !== undefined && e.hbu !== f.hbu)
|
|
45
|
+
return false;
|
|
46
|
+
if (f.supervisor !== undefined && e.supervisor !== f.supervisor)
|
|
47
|
+
return false;
|
|
48
|
+
if (f.payClass !== undefined && e.payClass !== f.payClass)
|
|
49
|
+
return false;
|
|
50
|
+
if (f.jobType !== undefined && e.jobType !== f.jobType)
|
|
51
|
+
return false;
|
|
52
|
+
if (f.jobStep !== undefined && e.jobStep !== f.jobStep)
|
|
53
|
+
return false;
|
|
54
|
+
if (f.sector !== undefined && e.sector !== f.sector)
|
|
55
|
+
return false;
|
|
56
|
+
if (f.division !== undefined && e.division !== f.division)
|
|
57
|
+
return false;
|
|
58
|
+
if (f.q) {
|
|
59
|
+
const q = f.q.toLowerCase();
|
|
60
|
+
const name = e.name?.toLowerCase() ?? '';
|
|
61
|
+
const email = e.email?.toLowerCase() ?? '';
|
|
62
|
+
if (!name.includes(q) && !email.includes(q))
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function applyWorkorderFilters(data, f) {
|
|
69
|
+
if (!f)
|
|
70
|
+
return data;
|
|
71
|
+
return data.filter((w) => {
|
|
72
|
+
if (f.businessUnitId !== undefined && w.businessUnitId !== f.businessUnitId)
|
|
73
|
+
return false;
|
|
74
|
+
if (f.costCodeId !== undefined && w.costCodeId !== f.costCodeId)
|
|
75
|
+
return false;
|
|
76
|
+
if (f.isActive !== undefined && w.isActive !== f.isActive)
|
|
77
|
+
return false;
|
|
78
|
+
if (f.completed !== undefined && w.completed !== f.completed)
|
|
79
|
+
return false;
|
|
80
|
+
if (f.area !== undefined && w.area !== f.area)
|
|
81
|
+
return false;
|
|
82
|
+
if (f.parentWorkOrder !== undefined && w.parentWorkOrder !== f.parentWorkOrder)
|
|
83
|
+
return false;
|
|
84
|
+
if (f.q) {
|
|
85
|
+
const q = f.q.toLowerCase();
|
|
86
|
+
const desc = w.description?.toLowerCase() ?? '';
|
|
87
|
+
const wo = w.clientWorkOrderId?.toLowerCase() ?? '';
|
|
88
|
+
if (!desc.includes(q) && !wo.includes(q))
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function applyPaytypeFilters(data, f) {
|
|
95
|
+
if (!f)
|
|
96
|
+
return data;
|
|
97
|
+
return data.filter((p) => {
|
|
98
|
+
if (f.payClass !== undefined && p.payClass !== f.payClass)
|
|
99
|
+
return false;
|
|
100
|
+
if (f.category !== undefined && p.category !== f.category)
|
|
101
|
+
return false;
|
|
102
|
+
if (f.type !== undefined && p.type !== f.type)
|
|
103
|
+
return false;
|
|
104
|
+
if (f.isActive !== undefined && p.isActive !== f.isActive)
|
|
105
|
+
return false;
|
|
106
|
+
if (f.perDiemPayType !== undefined && p.perDiemPayType !== f.perDiemPayType)
|
|
107
|
+
return false;
|
|
108
|
+
if (f.q) {
|
|
109
|
+
const q = f.q.toLowerCase();
|
|
110
|
+
if (!p.description.toLowerCase().includes(q))
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function applyBusinessUnitFilters(data, f) {
|
|
117
|
+
if (!f)
|
|
118
|
+
return data;
|
|
119
|
+
return data.filter((b) => {
|
|
120
|
+
if (f.subsector !== undefined && b.subsector !== f.subsector)
|
|
121
|
+
return false;
|
|
122
|
+
if (f.isActive !== undefined && b.isActive !== f.isActive)
|
|
123
|
+
return false;
|
|
124
|
+
if (f.clientId !== undefined && b.clientId !== f.clientId)
|
|
125
|
+
return false;
|
|
126
|
+
if (f.q) {
|
|
127
|
+
const q = f.q.toLowerCase();
|
|
128
|
+
const desc = b.description.toLowerCase();
|
|
129
|
+
const client = b.clientDescription?.toLowerCase() ?? '';
|
|
130
|
+
if (!desc.includes(q) && !client.includes(q))
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function applyJobtypejobstepFilters(data, f) {
|
|
137
|
+
if (!f)
|
|
138
|
+
return data;
|
|
139
|
+
return data.filter((j) => {
|
|
140
|
+
if (f.jobType !== undefined && j.jobType !== f.jobType)
|
|
141
|
+
return false;
|
|
142
|
+
if (f.payclass !== undefined && j.payclass !== f.payclass)
|
|
143
|
+
return false;
|
|
144
|
+
if (f.isActive !== undefined && j.isActive !== f.isActive)
|
|
145
|
+
return false;
|
|
146
|
+
if (f.grp !== undefined && j.grp !== f.grp)
|
|
147
|
+
return false;
|
|
148
|
+
if (f.q) {
|
|
149
|
+
const q = f.q.toLowerCase();
|
|
150
|
+
const desc = j.description?.toLowerCase() ?? '';
|
|
151
|
+
const jt = j.jobType?.toLowerCase() ?? '';
|
|
152
|
+
const js = j.jobStep?.toLowerCase() ?? '';
|
|
153
|
+
if (!desc.includes(q) && !jt.includes(q) && !js.includes(q))
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Costcodes filter is async because payTypeCode requires a cross-reference
|
|
160
|
+
async function applyCostcodeFilters(data, f) {
|
|
161
|
+
if (!f)
|
|
162
|
+
return data;
|
|
163
|
+
// Resolve payTypeCode → objectAccount
|
|
164
|
+
let payTypeObjectAccount;
|
|
165
|
+
if (f.payTypeCode !== undefined) {
|
|
166
|
+
const allPaytypes = await loadCached('paytypes', () => _getPaytypes());
|
|
167
|
+
payTypeObjectAccount = allPaytypes.find((p) => p.id === f.payTypeCode)?.objectAccount;
|
|
168
|
+
}
|
|
169
|
+
return data.filter((c) => {
|
|
170
|
+
if (f.businessUnitId !== undefined && c.businessUnitId !== f.businessUnitId)
|
|
171
|
+
return false;
|
|
172
|
+
if (f.isActive !== undefined && c.isActive !== f.isActive)
|
|
173
|
+
return false;
|
|
174
|
+
if (f.entryFlag !== undefined && c.entryFlag !== f.entryFlag)
|
|
175
|
+
return false;
|
|
176
|
+
if (f.payTypeCode !== undefined) {
|
|
177
|
+
// If paytype has an objectAccount, cost code must match it
|
|
178
|
+
if (payTypeObjectAccount && c.objectAccount !== payTypeObjectAccount)
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if (f.q) {
|
|
182
|
+
const q = f.q.toLowerCase();
|
|
183
|
+
const desc = c.description?.toLowerCase() ?? '';
|
|
184
|
+
const code = c.jdeCostCode?.toLowerCase() ?? '';
|
|
185
|
+
if (!desc.includes(q) && !code.includes(q))
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Public API — Employees
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
export async function getEmployees(filters) {
|
|
195
|
+
const all = await loadCached('employees', () => _getEmployees());
|
|
196
|
+
return applyEmployeeFilters(all, filters);
|
|
197
|
+
}
|
|
198
|
+
export async function getEmployeesDropdown(filters) {
|
|
199
|
+
const results = await getEmployees(filters);
|
|
200
|
+
return results.map((e) => ({ value: e.employeeId, label: e.name ?? e.employeeId }));
|
|
201
|
+
}
|
|
202
|
+
/** Single employee by ID — always fetches fresh (no IndexedDB). */
|
|
203
|
+
export async function getEmployee(employeeId) {
|
|
204
|
+
return _getEmployee(employeeId);
|
|
205
|
+
}
|
|
206
|
+
/** Single employee by ID including compensation fields — always fetches fresh (no IndexedDB). */
|
|
207
|
+
export async function getEmployeePrivileged(employeeId) {
|
|
208
|
+
return _getEmployeePrivileged(employeeId);
|
|
209
|
+
}
|
|
210
|
+
/** Full supervisor chain above an employee — always fetches fresh. */
|
|
211
|
+
export async function getSupervisorChain(employeeId) {
|
|
212
|
+
return _getSupervisorChain(employeeId);
|
|
213
|
+
}
|
|
214
|
+
/** Look up JDE number and employee from email — always fetches fresh. */
|
|
215
|
+
export async function getJdeFromEmail(email) {
|
|
216
|
+
return _getJdeFromEmail(email);
|
|
217
|
+
}
|
|
218
|
+
/** Verify employee identity — always fetches fresh. */
|
|
219
|
+
export async function verifyIdentity(inputs) {
|
|
220
|
+
return _verifyIdentity(inputs);
|
|
221
|
+
}
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
// Public API — Workorders
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
export async function getWorkorders(filters) {
|
|
226
|
+
const all = await loadCached('workorders', () => _getWorkorders());
|
|
227
|
+
return applyWorkorderFilters(all, filters);
|
|
228
|
+
}
|
|
229
|
+
export async function getWorkordersDropdown(filters) {
|
|
230
|
+
const results = await getWorkorders({ isActive: true, ...filters });
|
|
231
|
+
return results.map((w) => ({ value: w.id, label: w.description ?? w.id }));
|
|
232
|
+
}
|
|
233
|
+
/** Single workorder by ID — always fetches fresh (no IndexedDB). */
|
|
234
|
+
export async function getWorkorder(id) {
|
|
235
|
+
return _getWorkorder(id);
|
|
236
|
+
}
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// Public API — Cost Codes
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
export async function getCostcodes(filters) {
|
|
241
|
+
const all = await loadCached('costcodes', () => _getCostcodes());
|
|
242
|
+
return applyCostcodeFilters(all, filters);
|
|
243
|
+
}
|
|
244
|
+
export async function getCostcodesDropdown(filters) {
|
|
245
|
+
const mergedFilters = { isActive: true, entryFlag: true, ...filters };
|
|
246
|
+
const results = await getCostcodes(mergedFilters);
|
|
247
|
+
const now = new Date();
|
|
248
|
+
return results
|
|
249
|
+
.filter((c) => !c.expirationDate || new Date(c.expirationDate) >= now)
|
|
250
|
+
.map((c) => ({
|
|
251
|
+
value: c.id,
|
|
252
|
+
label: `${c.jdeCostCode ?? c.id} - ${c.description ?? ''}`,
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
/** Single cost code by ID — always fetches fresh (no IndexedDB). */
|
|
256
|
+
export async function getCostcode(id) {
|
|
257
|
+
return _getCostcode(id);
|
|
258
|
+
}
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// Public API — Pay Types
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
export async function getPaytypes(filters) {
|
|
263
|
+
const all = await loadCached('paytypes', () => _getPaytypes());
|
|
264
|
+
return applyPaytypeFilters(all, filters);
|
|
265
|
+
}
|
|
266
|
+
export async function getPaytypesDropdown(filters) {
|
|
267
|
+
const results = await getPaytypes(filters);
|
|
268
|
+
return results.map((p) => ({ value: p.id, label: p.description, payClass: p.payClass }));
|
|
269
|
+
}
|
|
270
|
+
/** Single pay type by ID — always fetches fresh (no IndexedDB). */
|
|
271
|
+
export async function getPaytype(id) {
|
|
272
|
+
return _getPaytype(id);
|
|
273
|
+
}
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// Public API — Business Units
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
export async function getBusinessUnits(filters) {
|
|
278
|
+
const all = await loadCached('businessUnits', () => _getBusinessUnits());
|
|
279
|
+
return applyBusinessUnitFilters(all, filters);
|
|
280
|
+
}
|
|
281
|
+
export async function getBusinessUnitsDropdown(filters) {
|
|
282
|
+
const results = await getBusinessUnits(filters);
|
|
283
|
+
return results.map((b) => ({ value: b.id, label: b.description }));
|
|
284
|
+
}
|
|
285
|
+
/** Single business unit by ID — always fetches fresh (no IndexedDB). */
|
|
286
|
+
export async function getBusinessUnit(id) {
|
|
287
|
+
return _getBusinessUnit(id);
|
|
288
|
+
}
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
// Public API — Job Type / Job Steps
|
|
291
|
+
// ---------------------------------------------------------------------------
|
|
292
|
+
export async function getJobtypejobsteps(filters) {
|
|
293
|
+
const all = await loadCached('jobtypejobsteps', () => _getJobtypejobsteps());
|
|
294
|
+
return applyJobtypejobstepFilters(all, filters);
|
|
295
|
+
}
|
|
296
|
+
export async function getJobtypejobstepsDropdown(filters) {
|
|
297
|
+
const results = await getJobtypejobsteps(filters);
|
|
298
|
+
return results.map((j) => ({
|
|
299
|
+
value: j.id,
|
|
300
|
+
label: j.description ?? `${j.jobType ?? ''} ${j.jobStep ?? ''}`.trim(),
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
/** Single job type/job step by ID — always fetches fresh (no IndexedDB). */
|
|
304
|
+
export async function getJobtypejobstep(id) {
|
|
305
|
+
return _getJobtypejobstep(id);
|
|
306
|
+
}
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// Cache management
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
/**
|
|
311
|
+
* Clear the IndexedDB cache for a specific entity, or all entities.
|
|
312
|
+
*
|
|
313
|
+
* Call after mutations to ensure the next read fetches fresh data from
|
|
314
|
+
* the server instead of returning stale cached results.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* await createWorkorder(data)
|
|
318
|
+
* clearCache('workorders') // next getWorkorders() will re-fetch
|
|
319
|
+
*
|
|
320
|
+
* clearCache() // clear everything
|
|
321
|
+
*/
|
|
322
|
+
export function clearCache(entity) {
|
|
323
|
+
idbClear(entity).catch(() => { });
|
|
324
|
+
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export declare const getCostcodes:
|
|
2
|
-
export declare const getCostcodesDropdown:
|
|
3
|
-
export declare const getCostcode:
|
|
4
|
-
export declare const getCostcodesDropdownByBu: any;
|
|
5
|
-
export declare const getCostcodesDropdownByBuAndPayType: any;
|
|
6
|
-
export declare const searchCostcodes: any;
|
|
1
|
+
export declare const getCostcodes: import("@sveltejs/kit").RemoteQueryFunction<void, import("./index.js").Costcode[]>;
|
|
2
|
+
export declare const getCostcodesDropdown: import("@sveltejs/kit").RemoteQueryFunction<void, import("./index.js").DropdownOption[]>;
|
|
3
|
+
export declare const getCostcode: import("@sveltejs/kit").RemoteQueryFunction<string, import("./index.js").Costcode>;
|
package/dist/costcodes.remote.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { query } from '$app/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { getClient } from './client.js';
|
|
4
|
-
const buPayTypeSchema = z.object({
|
|
5
|
-
businessUnitId: z.string(),
|
|
6
|
-
payTypeCode: z.string(),
|
|
7
|
-
});
|
|
8
4
|
export const getCostcodes = query(async () => getClient().getCostcodes());
|
|
9
5
|
export const getCostcodesDropdown = query(async () => getClient().getCostcodesDropdown());
|
|
10
6
|
export const getCostcode = query(z.string(), async (id) => getClient().getCostcode(id));
|
|
11
|
-
export const getCostcodesDropdownByBu = query(z.string(), async (businessUnitId) => getClient().getCostcodesDropdownByBu(businessUnitId));
|
|
12
|
-
export const getCostcodesDropdownByBuAndPayType = query(buPayTypeSchema, async ({ businessUnitId, payTypeCode }) => getClient().getCostcodesDropdownByBuAndPayType(businessUnitId, payTypeCode));
|
|
13
|
-
export const searchCostcodes = query(z.string(), async (q) => getClient().searchCostcodes(q));
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
export declare const getEmployees:
|
|
2
|
-
export declare const getEmployeesDropdown:
|
|
3
|
-
export declare const getEmployee:
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare const verifyIdentity:
|
|
1
|
+
export declare const getEmployees: import("@sveltejs/kit").RemoteQueryFunction<void, import("./index.js").Employee[]>;
|
|
2
|
+
export declare const getEmployeesDropdown: import("@sveltejs/kit").RemoteQueryFunction<void, import("./index.js").DropdownOption[]>;
|
|
3
|
+
export declare const getEmployee: import("@sveltejs/kit").RemoteQueryFunction<string, import("./index.js").Employee>;
|
|
4
|
+
export declare const getEmployeePrivileged: import("@sveltejs/kit").RemoteQueryFunction<string, import("./index.js").EmployeePrivileged>;
|
|
5
|
+
export declare const getSupervisorChain: import("@sveltejs/kit").RemoteQueryFunction<string, import("./index.js").Employee[]>;
|
|
6
|
+
export declare const getJdeFromEmail: import("@sveltejs/kit").RemoteQueryFunction<string, {
|
|
7
|
+
jde: string | null;
|
|
8
|
+
employee: import("./index.js").Employee | null;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const verifyIdentity: import("@sveltejs/kit").RemoteCommand<{
|
|
11
|
+
first3FirstName: string;
|
|
12
|
+
first3LastName: string;
|
|
13
|
+
dob: string;
|
|
14
|
+
ssn4: string;
|
|
15
|
+
}, Promise<import("./index.js").Employee | null>>;
|
package/dist/employees.remote.js
CHANGED
|
@@ -11,10 +11,7 @@ const verifyIdentitySchema = z.object({
|
|
|
11
11
|
export const getEmployees = query(async () => getClient().getEmployees());
|
|
12
12
|
export const getEmployeesDropdown = query(async () => getClient().getEmployeesDropdown());
|
|
13
13
|
export const getEmployee = query(employeeIdSchema, async (employeeId) => getClient().getEmployee(employeeId));
|
|
14
|
-
export const
|
|
15
|
-
export const getBySupervisor = query(employeeIdSchema, async (supervisorId) => getClient().getBySupervisor(supervisorId));
|
|
16
|
-
export const searchByEmail = query(z.string(), async (email) => getClient().searchByEmail(email));
|
|
14
|
+
export const getEmployeePrivileged = query(employeeIdSchema, async (employeeId) => getClient().getEmployeePrivileged(employeeId));
|
|
17
15
|
export const getSupervisorChain = query(employeeIdSchema, async (employeeId) => getClient().getSupervisorChain(employeeId));
|
|
18
16
|
export const getJdeFromEmail = query(z.string(), async (email) => getClient().getJdeFromEmail(email));
|
|
19
|
-
export const searchByHbu = query(z.string(), async (hbu) => getClient().searchByHbu(hbu));
|
|
20
17
|
export const verifyIdentity = command(verifyIdentitySchema, async (inputs) => getClient().verifyIdentity(inputs));
|
package/dist/idb.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const STORES: readonly ["workorders", "employees", "costcodes", "paytypes", "businessUnits", "jobtypejobsteps"];
|
|
2
|
+
export type IdbStore = (typeof STORES)[number];
|
|
3
|
+
interface IdbEntry<T> {
|
|
4
|
+
data: T;
|
|
5
|
+
fetchedAt: number;
|
|
6
|
+
}
|
|
7
|
+
/** Get a cached entry. Returns null in SSR (no window) or on cache miss. */
|
|
8
|
+
export declare function idbGet<T>(store: IdbStore, key: string): Promise<IdbEntry<T> | null>;
|
|
9
|
+
/** Store a value with the current timestamp. */
|
|
10
|
+
export declare function idbSet<T>(store: IdbStore, key: string, data: T): Promise<void>;
|
|
11
|
+
/** Clear a specific store, or all stores when called with no argument. */
|
|
12
|
+
export declare function idbClear(store?: IdbStore): Promise<void>;
|
|
13
|
+
export {};
|
package/dist/idb.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const DB_NAME = 'apihub-cache';
|
|
2
|
+
const DB_VERSION = 1;
|
|
3
|
+
const STORES = [
|
|
4
|
+
'workorders',
|
|
5
|
+
'employees',
|
|
6
|
+
'costcodes',
|
|
7
|
+
'paytypes',
|
|
8
|
+
'businessUnits',
|
|
9
|
+
'jobtypejobsteps',
|
|
10
|
+
];
|
|
11
|
+
function openDb() {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
14
|
+
req.onupgradeneeded = () => {
|
|
15
|
+
const db = req.result;
|
|
16
|
+
for (const store of STORES) {
|
|
17
|
+
if (!db.objectStoreNames.contains(store)) {
|
|
18
|
+
db.createObjectStore(store);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
req.onsuccess = () => resolve(req.result);
|
|
23
|
+
req.onerror = () => reject(req.error);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Get a cached entry. Returns null in SSR (no window) or on cache miss. */
|
|
27
|
+
export async function idbGet(store, key) {
|
|
28
|
+
if (typeof window === 'undefined')
|
|
29
|
+
return null;
|
|
30
|
+
try {
|
|
31
|
+
const db = await openDb();
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const tx = db.transaction(store, 'readonly');
|
|
34
|
+
const req = tx.objectStore(store).get(key);
|
|
35
|
+
req.onsuccess = () => resolve(req.result ?? null);
|
|
36
|
+
req.onerror = () => reject(req.error);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Store a value with the current timestamp. */
|
|
44
|
+
export async function idbSet(store, key, data) {
|
|
45
|
+
if (typeof window === 'undefined')
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
const db = await openDb();
|
|
49
|
+
await new Promise((resolve, reject) => {
|
|
50
|
+
const tx = db.transaction(store, 'readwrite');
|
|
51
|
+
const req = tx.objectStore(store).put({ data, fetchedAt: Date.now() }, key);
|
|
52
|
+
req.onsuccess = () => resolve();
|
|
53
|
+
req.onerror = () => reject(req.error);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Ignore write failures — cache is best-effort
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Clear a specific store, or all stores when called with no argument. */
|
|
61
|
+
export async function idbClear(store) {
|
|
62
|
+
if (typeof window === 'undefined')
|
|
63
|
+
return;
|
|
64
|
+
try {
|
|
65
|
+
const db = await openDb();
|
|
66
|
+
const storeNames = store ? [store] : [...STORES];
|
|
67
|
+
await new Promise((resolve, reject) => {
|
|
68
|
+
const tx = db.transaction(storeNames, 'readwrite');
|
|
69
|
+
for (const s of storeNames) {
|
|
70
|
+
tx.objectStore(s).clear();
|
|
71
|
+
}
|
|
72
|
+
tx.oncomplete = () => resolve();
|
|
73
|
+
tx.onerror = () => reject(tx.error);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Ignore failures
|
|
78
|
+
}
|
|
79
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ export interface Employee {
|
|
|
5
5
|
employeeId: string;
|
|
6
6
|
name: string | null;
|
|
7
7
|
email: string | null;
|
|
8
|
+
personalEmail: string | null;
|
|
9
|
+
clientEmail: string | null;
|
|
10
|
+
workEmail: string | null;
|
|
8
11
|
badgeNumber: string | null;
|
|
9
12
|
employementStatus: string | null;
|
|
10
13
|
residentTaxArea: string | null;
|
|
@@ -21,8 +24,6 @@ export interface Employee {
|
|
|
21
24
|
jobDescription: string | null;
|
|
22
25
|
workSchedule: string | null;
|
|
23
26
|
shift: string | null;
|
|
24
|
-
hourlyRate: string | null;
|
|
25
|
-
annualSalary: string | null;
|
|
26
27
|
termDate: string | null;
|
|
27
28
|
hireDate: string | null;
|
|
28
29
|
topFlexPtoDate: string | null;
|
|
@@ -47,6 +48,10 @@ export interface Employee {
|
|
|
47
48
|
updatedAtJulian: number | null;
|
|
48
49
|
updatedAt: string | null;
|
|
49
50
|
}
|
|
51
|
+
export interface EmployeePrivileged extends Employee {
|
|
52
|
+
hourlyRate: string | null;
|
|
53
|
+
annualSalary: string | null;
|
|
54
|
+
}
|
|
50
55
|
export interface ApiHubClientOptions {
|
|
51
56
|
baseUrl: string;
|
|
52
57
|
apiKey: string;
|
|
@@ -215,6 +220,8 @@ export declare class ApiHubClient {
|
|
|
215
220
|
getEmployeesDropdown(): Promise<DropdownOption[]>;
|
|
216
221
|
/** Get a single employee by employeeId */
|
|
217
222
|
getEmployee(employeeId: string): Promise<Employee>;
|
|
223
|
+
/** Get a single employee with compensation fields by employeeId */
|
|
224
|
+
getEmployeePrivileged(employeeId: string): Promise<EmployeePrivileged>;
|
|
218
225
|
/** Search employees by name (case-insensitive partial match) */
|
|
219
226
|
searchByName(name: string): Promise<Employee[]>;
|
|
220
227
|
/** Get all employees reporting to a supervisor */
|