@salesforce/ui-bundle-template-app-react-sample-b2e 11.20.0 → 11.21.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.
Files changed (102) hide show
  1. package/dist/CHANGELOG.md +8 -0
  2. package/dist/force-app/main/default/uiBundles/propertymanagementapp/package.json +4 -4
  3. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/applications/applicationSearchService.ts +25 -43
  4. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceRequests/maintenanceRequestSearchService.ts +31 -65
  5. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceWorkers/maintenanceWorkerSearchService.ts +21 -43
  6. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/properties/propertySearchService.ts +33 -53
  7. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/applications/ApplicationCard.tsx +80 -0
  8. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/dashboard/GlobalSearchBar.tsx +2 -2
  9. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/layout/VerticalNav.tsx +28 -18
  10. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/maintenanceRequests/MaintenanceRequestCard.tsx +79 -52
  11. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/maintenanceWorkers/WorkerCard.tsx +87 -0
  12. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/search/UnifiedSearch.tsx +213 -0
  13. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/api/distinctValuesService.ts +84 -0
  14. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/api/searchService.ts +71 -0
  15. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/MergedSearchResults.tsx +263 -0
  16. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/Search.tsx +185 -0
  17. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/SearchResults.tsx +77 -0
  18. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/SourceSection.tsx +166 -0
  19. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/controls/PaginationControls.tsx +185 -0
  20. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/controls/ScopeSelector.tsx +55 -0
  21. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/controls/SearchBar.tsx +55 -0
  22. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/controls/SortControl.tsx +62 -0
  23. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/ActiveFilters.tsx +61 -0
  24. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/DefaultFilterPanel.tsx +125 -0
  25. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/{object-search/components → search/components/filters}/FilterContext.tsx +7 -20
  26. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/BooleanFilter.tsx +50 -0
  27. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/DateRangeFilter.tsx +160 -0
  28. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/FilterFieldWrapper.tsx +26 -0
  29. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/MultiSelectFilter.tsx +88 -0
  30. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/NumericRangeFilter.tsx +78 -0
  31. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/SelectFilter.tsx +46 -0
  32. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/filters/inputs/TextFilter.tsx +52 -0
  33. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/components/results/DefaultResultRow.tsx +109 -0
  34. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/config.json +83 -0
  35. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/{object-search → search}/hooks/useAsyncData.ts +3 -10
  36. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/hooks/useDistinctValues.ts +59 -0
  37. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/hooks/useSearch.ts +703 -0
  38. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/index.ts +90 -0
  39. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/loadConfig.ts +14 -0
  40. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/queryBuilder.ts +156 -0
  41. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/types.ts +307 -0
  42. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/utils/debounce.ts +17 -0
  43. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/utils/fieldUtils.ts +14 -0
  44. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/utils/filterUtils.ts +285 -0
  45. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/search/utils/sortUtils.ts +34 -0
  46. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/lib/constants.ts +16 -29
  47. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/lib/routeConfig.ts +1 -0
  48. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/lib/searchConfig.ts +190 -0
  49. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/ApplicationSearch.tsx +8 -385
  50. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/Home.tsx +4 -2
  51. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/MaintenanceRequestSearch.tsx +8 -458
  52. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/MaintenanceWorkerSearch.tsx +8 -341
  53. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/PropertySearch.tsx +7 -243
  54. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/Search.tsx +16 -0
  55. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/routes.tsx +6 -0
  56. package/dist/force-app/main/default/uiBundles/propertymanagementapp/tsconfig.tsbuildinfo +1 -1
  57. package/dist/package-lock.json +2 -2
  58. package/dist/package.json +1 -1
  59. package/package.json +2 -2
  60. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/applications/query/distinctApplicationStatus.graphql +0 -19
  61. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/applications/query/searchApplications.graphql +0 -65
  62. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceRequests/query/distinctMaintenanceRequestPriority.graphql +0 -19
  63. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceRequests/query/distinctMaintenanceRequestStatus.graphql +0 -19
  64. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceRequests/query/distinctMaintenanceRequestType.graphql +0 -19
  65. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceRequests/query/searchMaintenanceRequests.graphql +0 -82
  66. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceWorkers/query/distinctMaintenanceWorkerEmploymentType.graphql +0 -19
  67. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/maintenanceWorkers/query/searchMaintenanceWorkers.graphql +0 -64
  68. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/properties/query/distinctPropertyStatus.graphql +0 -19
  69. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/properties/query/distinctPropertyType.graphql +0 -19
  70. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/properties/query/searchProperties.graphql +0 -105
  71. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/shared/ObjectSearchErrorState.tsx +0 -45
  72. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/shared/UserAvatar.tsx +0 -35
  73. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/api/accountSearchService.ts +0 -46
  74. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/api/query/distinctAccountIndustries.graphql +0 -19
  75. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/api/query/distinctAccountTypes.graphql +0 -19
  76. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/api/query/getAccountDetail.graphql +0 -121
  77. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/api/query/searchAccounts.graphql +0 -51
  78. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/pages/AccountObjectDetailPage.tsx +0 -355
  79. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/pages/AccountSearch.tsx +0 -304
  80. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/pages/Home.tsx +0 -34
  81. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/api/objectSearchService.ts +0 -82
  82. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/ActiveFilters.tsx +0 -89
  83. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/ObjectBreadcrumb.tsx +0 -66
  84. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/PaginationControls.tsx +0 -109
  85. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/SearchBar.tsx +0 -41
  86. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/SortControl.tsx +0 -143
  87. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/BooleanFilter.tsx +0 -78
  88. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/DateFilter.tsx +0 -128
  89. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/DateRangeFilter.tsx +0 -70
  90. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/FilterFieldWrapper.tsx +0 -43
  91. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/MultiSelectFilter.tsx +0 -105
  92. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/NumericRangeFilter.tsx +0 -171
  93. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/SearchFilter.tsx +0 -52
  94. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/SelectFilter.tsx +0 -97
  95. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/TextFilter.tsx +0 -93
  96. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/hooks/useDebouncedCallback.ts +0 -34
  97. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/hooks/useObjectSearchParams.ts +0 -254
  98. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/utils/debounce.ts +0 -25
  99. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/utils/fieldUtils.ts +0 -29
  100. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/utils/filterUtils.ts +0 -404
  101. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/utils/sortUtils.ts +0 -38
  102. package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/lib/filterUtils.ts +0 -11
package/dist/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [11.21.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.20.0...v11.21.0) (2026-07-10)
7
+
8
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
9
+
10
+
11
+
12
+
13
+
6
14
  ## [11.20.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.19.0...v11.20.0) (2026-07-10)
7
15
 
8
16
  **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
@@ -18,8 +18,8 @@
18
18
  "graphql:schema": "node scripts/get-graphql-schema.mjs"
19
19
  },
20
20
  "dependencies": {
21
- "@salesforce/platform-sdk": "^11.20.0",
22
- "@salesforce/ui-bundle": "^11.20.0",
21
+ "@salesforce/platform-sdk": "^11.21.0",
22
+ "@salesforce/ui-bundle": "^11.21.0",
23
23
  "@tailwindcss/vite": "^4.1.17",
24
24
  "class-variance-authority": "^0.7.1",
25
25
  "clsx": "^2.1.1",
@@ -46,8 +46,8 @@
46
46
  "@graphql-eslint/eslint-plugin": "^4.1.0",
47
47
  "@graphql-tools/utils": "^11.0.0",
48
48
  "@playwright/test": "^1.49.0",
49
- "@salesforce/graphiti": "^11.20.0",
50
- "@salesforce/vite-plugin-ui-bundle": "^11.20.0",
49
+ "@salesforce/graphiti": "^11.21.0",
50
+ "@salesforce/vite-plugin-ui-bundle": "^11.21.0",
51
51
  "@testing-library/jest-dom": "^6.6.3",
52
52
  "@testing-library/react": "^16.1.0",
53
53
  "@testing-library/user-event": "^14.5.2",
@@ -1,46 +1,28 @@
1
- import SEARCH_QUERY from "./query/searchApplications.graphql?raw";
2
- import DISTINCT_STATUS_QUERY from "./query/distinctApplicationStatus.graphql?raw";
3
- import {
4
- searchObjects,
5
- fetchDistinctValues,
6
- type ObjectSearchOptions,
7
- type PicklistOption,
8
- } from "../../features/object-search/api/objectSearchService";
9
- import type {
10
- SearchApplicationsQuery,
11
- SearchApplicationsQueryVariables,
12
- DistinctApplicationStatusQuery,
13
- } from "../graphql-operations-types";
1
+ /**
2
+ * Application search result types.
3
+ *
4
+ * Search itself is now driven by feature-react-search (see `lib/searchConfig.ts`),
5
+ * which builds and runs its GraphQL at runtime — there is no generated
6
+ * `SearchApplicationsQuery` operation type to derive from. This module declares the
7
+ * node shape that the result card and detail modal read, mirroring the Salesforce
8
+ * UI API field-wrapper shape (`{ value, displayValue }`).
9
+ */
14
10
 
15
- export type ApplicationSearchResult = NonNullable<
16
- SearchApplicationsQuery["uiapi"]["query"]["Application__c"]
17
- >;
11
+ /** A Salesforce UI API scalar field wrapper. */
12
+ type Field<T> = { value?: T | null; displayValue?: string | null } | null;
18
13
 
19
- export type ApplicationSearchNode = NonNullable<
20
- NonNullable<NonNullable<ApplicationSearchResult["edges"]>[number]>["node"]
21
- >;
22
-
23
- export type ApplicationSearchOptions = ObjectSearchOptions<
24
- SearchApplicationsQueryVariables["where"],
25
- SearchApplicationsQueryVariables["orderBy"]
26
- >;
27
-
28
- export type { PicklistOption };
29
-
30
- export async function searchApplications(
31
- options: ApplicationSearchOptions = {},
32
- ): Promise<ApplicationSearchResult> {
33
- return searchObjects<
34
- ApplicationSearchResult,
35
- SearchApplicationsQuery,
36
- SearchApplicationsQueryVariables
37
- >(SEARCH_QUERY, "Application__c", options);
38
- }
39
-
40
- export async function fetchDistinctApplicationStatus(): Promise<PicklistOption[]> {
41
- return fetchDistinctValues<DistinctApplicationStatusQuery>(
42
- DISTINCT_STATUS_QUERY,
43
- "Application__c",
44
- "Status__c",
45
- );
14
+ export interface ApplicationSearchNode {
15
+ Id: string;
16
+ Name?: Field<string>;
17
+ Status__c?: Field<string>;
18
+ Start_Date__c?: Field<string>;
19
+ Employment__c?: Field<string>;
20
+ References__c?: Field<string>;
21
+ User__r?: {
22
+ Name?: Field<string>;
23
+ } | null;
24
+ Property__r?: {
25
+ Name?: Field<string>;
26
+ Address__c?: Field<string>;
27
+ } | null;
46
28
  }
@@ -1,66 +1,32 @@
1
- import SEARCH_QUERY from "./query/searchMaintenanceRequests.graphql?raw";
2
- import DISTINCT_STATUS_QUERY from "./query/distinctMaintenanceRequestStatus.graphql?raw";
3
- import DISTINCT_TYPE_QUERY from "./query/distinctMaintenanceRequestType.graphql?raw";
4
- import DISTINCT_PRIORITY_QUERY from "./query/distinctMaintenanceRequestPriority.graphql?raw";
5
- import {
6
- searchObjects,
7
- fetchDistinctValues,
8
- type ObjectSearchOptions,
9
- type PicklistOption,
10
- } from "../../features/object-search/api/objectSearchService";
11
- import type {
12
- SearchMaintenanceRequestsQuery,
13
- SearchMaintenanceRequestsQueryVariables,
14
- DistinctMaintenanceRequestStatusQuery,
15
- DistinctMaintenanceRequestTypeQuery,
16
- DistinctMaintenanceRequestPriorityQuery,
17
- } from "../graphql-operations-types";
18
-
19
- export type MaintenanceRequestSearchResult = NonNullable<
20
- SearchMaintenanceRequestsQuery["uiapi"]["query"]["Maintenance_Request__c"]
21
- >;
22
-
23
- export type MaintenanceRequestSearchNode = NonNullable<
24
- NonNullable<NonNullable<MaintenanceRequestSearchResult["edges"]>[number]>["node"]
25
- >;
26
-
27
- export type MaintenanceRequestSearchOptions = ObjectSearchOptions<
28
- SearchMaintenanceRequestsQueryVariables["where"],
29
- SearchMaintenanceRequestsQueryVariables["orderBy"]
30
- >;
31
-
32
- export type { PicklistOption };
33
-
34
- export async function searchMaintenanceRequests(
35
- options: MaintenanceRequestSearchOptions = {},
36
- ): Promise<MaintenanceRequestSearchResult> {
37
- return searchObjects<
38
- MaintenanceRequestSearchResult,
39
- SearchMaintenanceRequestsQuery,
40
- SearchMaintenanceRequestsQueryVariables
41
- >(SEARCH_QUERY, "Maintenance_Request__c", options);
42
- }
43
-
44
- export async function fetchDistinctMaintenanceRequestStatus(): Promise<PicklistOption[]> {
45
- return fetchDistinctValues<DistinctMaintenanceRequestStatusQuery>(
46
- DISTINCT_STATUS_QUERY,
47
- "Maintenance_Request__c",
48
- "Status__c",
49
- );
50
- }
51
-
52
- export async function fetchDistinctMaintenanceRequestType(): Promise<PicklistOption[]> {
53
- return fetchDistinctValues<DistinctMaintenanceRequestTypeQuery>(
54
- DISTINCT_TYPE_QUERY,
55
- "Maintenance_Request__c",
56
- "Type__c",
57
- );
58
- }
59
-
60
- export async function fetchDistinctMaintenanceRequestPriority(): Promise<PicklistOption[]> {
61
- return fetchDistinctValues<DistinctMaintenanceRequestPriorityQuery>(
62
- DISTINCT_PRIORITY_QUERY,
63
- "Maintenance_Request__c",
64
- "Priority__c",
65
- );
1
+ /**
2
+ * Maintenance-request search result types.
3
+ *
4
+ * Search itself is now driven by feature-react-search (see `lib/searchConfig.ts`),
5
+ * which builds and runs its GraphQL at runtime — there is no generated
6
+ * `SearchMaintenanceRequestsQuery` operation type to derive from. This module
7
+ * declares the node shape that the result card and detail modal read, mirroring
8
+ * the Salesforce UI API field-wrapper shape (`{ value, displayValue }`).
9
+ */
10
+
11
+ /** A Salesforce UI API scalar field wrapper. */
12
+ type Field<T> = { value?: T | null; displayValue?: string | null } | null;
13
+
14
+ export interface MaintenanceRequestSearchNode {
15
+ Id: string;
16
+ Name?: Field<string>;
17
+ Type__c?: Field<string>;
18
+ Priority__c?: Field<string>;
19
+ Status__c?: Field<string>;
20
+ Description__c?: Field<string>;
21
+ Scheduled__c?: Field<string>;
22
+ Property__r?: {
23
+ Name?: Field<string>;
24
+ Address__c?: Field<string>;
25
+ } | null;
26
+ Assigned_Worker__r?: {
27
+ Name?: Field<string>;
28
+ } | null;
29
+ User__r?: {
30
+ Name?: Field<string>;
31
+ } | null;
66
32
  }
@@ -1,46 +1,24 @@
1
- import SEARCH_QUERY from "./query/searchMaintenanceWorkers.graphql?raw";
2
- import DISTINCT_TYPE_QUERY from "./query/distinctMaintenanceWorkerEmploymentType.graphql?raw";
3
- import {
4
- searchObjects,
5
- fetchDistinctValues,
6
- type ObjectSearchOptions,
7
- type PicklistOption,
8
- } from "../../features/object-search/api/objectSearchService";
9
- import type {
10
- SearchMaintenanceWorkersQuery,
11
- SearchMaintenanceWorkersQueryVariables,
12
- DistinctMaintenanceWorkerEmploymentTypeQuery,
13
- } from "../graphql-operations-types.js";
1
+ /**
2
+ * Maintenance-worker search result types.
3
+ *
4
+ * Search itself is now driven by feature-react-search (see `lib/searchConfig.ts`),
5
+ * which builds and runs its GraphQL at runtime — there is no generated
6
+ * `SearchMaintenanceWorkersQuery` operation type to derive from. This module
7
+ * declares the node shape that the result card and detail modal read, mirroring
8
+ * the Salesforce UI API field-wrapper shape (`{ value, displayValue }`).
9
+ */
14
10
 
15
- export type MaintenanceWorkerSearchResult = NonNullable<
16
- SearchMaintenanceWorkersQuery["uiapi"]["query"]["Maintenance_Worker__c"]
17
- >;
11
+ /** A Salesforce UI API scalar field wrapper. */
12
+ type Field<T> = { value?: T | null; displayValue?: string | null } | null;
18
13
 
19
- export type MaintenanceWorkerSearchNode = NonNullable<
20
- NonNullable<NonNullable<MaintenanceWorkerSearchResult["edges"]>[number]>["node"]
21
- >;
22
-
23
- export type MaintenanceWorkerSearchOptions = ObjectSearchOptions<
24
- SearchMaintenanceWorkersQueryVariables["where"],
25
- SearchMaintenanceWorkersQueryVariables["orderBy"]
26
- >;
27
-
28
- export type { PicklistOption };
29
-
30
- export async function searchMaintenanceWorkers(
31
- options: MaintenanceWorkerSearchOptions = {},
32
- ): Promise<MaintenanceWorkerSearchResult> {
33
- return searchObjects<
34
- MaintenanceWorkerSearchResult,
35
- SearchMaintenanceWorkersQuery,
36
- SearchMaintenanceWorkersQueryVariables
37
- >(SEARCH_QUERY, "Maintenance_Worker__c", options);
38
- }
39
-
40
- export async function fetchDistinctMaintenanceWorkerType(): Promise<PicklistOption[]> {
41
- return fetchDistinctValues<DistinctMaintenanceWorkerEmploymentTypeQuery>(
42
- DISTINCT_TYPE_QUERY,
43
- "Maintenance_Worker__c",
44
- "Employment_Type__c",
45
- );
14
+ export interface MaintenanceWorkerSearchNode {
15
+ Id: string;
16
+ Name?: Field<string>;
17
+ Employment_Type__c?: Field<string>;
18
+ Type__c?: Field<string>;
19
+ Phone__c?: Field<string>;
20
+ Location__c?: Field<string>;
21
+ Rating__c?: Field<number>;
22
+ Hourly_Rate__c?: Field<number>;
23
+ IsActive__c?: Field<boolean>;
46
24
  }
@@ -1,56 +1,36 @@
1
- import SEARCH_PROPERTIES_QUERY from "./query/searchProperties.graphql?raw";
2
- import DISTINCT_STATUS_QUERY from "./query/distinctPropertyStatus.graphql?raw";
3
- import DISTINCT_TYPE_QUERY from "./query/distinctPropertyType.graphql?raw";
4
- import {
5
- searchObjects,
6
- fetchDistinctValues,
7
- type ObjectSearchOptions,
8
- type PicklistOption,
9
- } from "../../features/object-search/api/objectSearchService";
10
- import type {
11
- SearchPropertiesQuery,
12
- SearchPropertiesQueryVariables,
13
- DistinctPropertyStatusQuery,
14
- DistinctPropertyTypeQuery,
15
- } from "../graphql-operations-types";
1
+ /**
2
+ * Property search result types.
3
+ *
4
+ * Search itself is now driven by feature-react-search (see `lib/searchConfig.ts`),
5
+ * which builds and runs its GraphQL at runtime — there is no generated
6
+ * `SearchPropertiesQuery` operation type to derive from. This module declares the
7
+ * node shape that the property result card and detail modal read, mirroring the
8
+ * Salesforce UI API field-wrapper shape (`{ value, displayValue }`).
9
+ */
16
10
 
17
- export type PropertySearchResult = NonNullable<
18
- SearchPropertiesQuery["uiapi"]["query"]["Property__c"]
19
- >;
11
+ /** A Salesforce UI API scalar field wrapper. */
12
+ type Field<T> = { value?: T | null; displayValue?: string | null } | null;
20
13
 
21
- export type PropertySearchNode = NonNullable<
22
- NonNullable<NonNullable<PropertySearchResult["edges"]>[number]>["node"]
23
- >;
24
-
25
- export type PropertySearchOptions = ObjectSearchOptions<
26
- SearchPropertiesQueryVariables["where"],
27
- SearchPropertiesQueryVariables["orderBy"]
28
- >;
29
-
30
- export type { PicklistOption };
31
-
32
- export async function searchProperties(
33
- options: PropertySearchOptions = {},
34
- ): Promise<PropertySearchResult> {
35
- return searchObjects<PropertySearchResult, SearchPropertiesQuery, SearchPropertiesQueryVariables>(
36
- SEARCH_PROPERTIES_QUERY,
37
- "Property__c",
38
- options,
39
- );
40
- }
41
-
42
- export async function fetchDistinctPropertyStatus(): Promise<PicklistOption[]> {
43
- return fetchDistinctValues<DistinctPropertyStatusQuery>(
44
- DISTINCT_STATUS_QUERY,
45
- "Property__c",
46
- "Status__c",
47
- );
48
- }
49
-
50
- export async function fetchDistinctPropertyType(): Promise<PicklistOption[]> {
51
- return fetchDistinctValues<DistinctPropertyTypeQuery>(
52
- DISTINCT_TYPE_QUERY,
53
- "Property__c",
54
- "Type__c",
55
- );
14
+ export interface PropertySearchNode {
15
+ Id: string;
16
+ Name?: Field<string>;
17
+ Address__c?: Field<string>;
18
+ Description__c?: Field<string>;
19
+ Type__c?: Field<string>;
20
+ Status__c?: Field<string>;
21
+ Hero_Image__c?: Field<string>;
22
+ Tour_URL__c?: Field<string>;
23
+ Features__c?: Field<string>;
24
+ Utilities__c?: Field<string>;
25
+ Available_Date__c?: Field<string>;
26
+ CreatedDate?: Field<string>;
27
+ Monthly_Rent__c?: Field<number>;
28
+ Bedrooms__c?: Field<number>;
29
+ Bathrooms__c?: Field<number>;
30
+ Sq_Ft__c?: Field<number>;
31
+ Year_Built__c?: Field<number>;
32
+ Deposit__c?: Field<number>;
33
+ Lease_Term__c?: Field<number>;
34
+ Parking__c?: Field<number>;
35
+ Pet_Friendly__c?: Field<boolean>;
56
36
  }
@@ -0,0 +1,80 @@
1
+ import React from "react";
2
+ import { FileText, User, Home, CalendarDays } from "lucide-react";
3
+ import type { ApplicationSearchNode } from "../../api/applications/applicationSearchService";
4
+
5
+ interface ApplicationCardProps {
6
+ application: ApplicationSearchNode;
7
+ onClick?: (application: ApplicationSearchNode) => void;
8
+ }
9
+
10
+ function statusColor(status: string): string {
11
+ const s = status.toLowerCase();
12
+ if (s.includes("approved")) return "bg-green-100 text-green-700";
13
+ if (s.includes("rejected")) return "bg-red-100 text-red-700";
14
+ if (s.includes("background")) return "bg-blue-100 text-blue-700";
15
+ if (s.includes("review")) return "bg-yellow-100 text-yellow-700";
16
+ return "bg-gray-100 text-gray-700";
17
+ }
18
+
19
+ function formatDate(value: string | null | undefined): string | undefined {
20
+ if (!value) return undefined;
21
+ const date = new Date(value);
22
+ if (isNaN(date.getTime())) return undefined;
23
+ return date.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" });
24
+ }
25
+
26
+ export const ApplicationCard: React.FC<ApplicationCardProps> = ({ application, onClick }) => {
27
+ const name = application.Name?.value || "Application";
28
+ const applicant = application.User__r?.Name?.value || "Unknown applicant";
29
+ const propertyName = application.Property__r?.Name?.value;
30
+ const propertyAddress = application.Property__r?.Address__c?.value;
31
+ const status = application.Status__c?.value || "Unknown";
32
+ const startDate = formatDate(application.Start_Date__c?.value);
33
+
34
+ const handleClick = () => onClick?.(application);
35
+
36
+ return (
37
+ <div
38
+ role="button"
39
+ tabIndex={0}
40
+ aria-label={name}
41
+ className="h-full bg-white rounded-lg shadow-md p-5 hover:shadow-lg transition-shadow cursor-pointer flex flex-col gap-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-purple focus-visible:ring-offset-2"
42
+ onClick={handleClick}
43
+ onKeyDown={(e) => {
44
+ if (e.key === "Enter" || e.key === " ") {
45
+ e.preventDefault();
46
+ handleClick();
47
+ }
48
+ }}
49
+ >
50
+ <div className="flex items-start justify-between gap-2">
51
+ <div className="flex items-center gap-2 min-w-0">
52
+ <FileText className="w-5 h-5 text-purple-600 shrink-0" />
53
+ <h3 className="text-base font-semibold text-gray-900 truncate">{name}</h3>
54
+ </div>
55
+ <span
56
+ className={`shrink-0 px-2.5 py-0.5 rounded-full text-xs font-medium ${statusColor(status)}`}
57
+ >
58
+ {status}
59
+ </span>
60
+ </div>
61
+
62
+ <div className="mt-auto space-y-1 text-sm text-gray-600">
63
+ <div className="flex items-center gap-2">
64
+ <User className="w-4 h-4 text-gray-400 shrink-0" />
65
+ <span className="truncate">{applicant}</span>
66
+ </div>
67
+ <div className="flex items-center gap-2">
68
+ <Home className="w-4 h-4 text-gray-400 shrink-0" />
69
+ <span className="truncate">{propertyName || propertyAddress || "Unknown property"}</span>
70
+ </div>
71
+ {startDate && (
72
+ <div className="flex items-center gap-2">
73
+ <CalendarDays className="w-4 h-4 text-gray-400 shrink-0" />
74
+ <span className="truncate">Starts {startDate}</span>
75
+ </div>
76
+ )}
77
+ </div>
78
+ </div>
79
+ );
80
+ };
@@ -92,9 +92,9 @@ export function GlobalSearchBar({
92
92
  type="button"
93
93
  onClick={onBrowseAll}
94
94
  className="px-4 py-3 text-sm font-medium text-[#372949] bg-white border border-gray-200 rounded-full shadow-sm hover:bg-gray-50 whitespace-nowrap"
95
- aria-label={`Browse all ${labelPlural}`}
95
+ aria-label={`Browse ${labelPlural}`}
96
96
  >
97
- Browse all {labelPlural}
97
+ Browse {labelPlural}
98
98
  </button>
99
99
  </div>
100
100
  );
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { Link, useLocation } from "react-router";
3
+ import { Search as SearchIcon } from "lucide-react";
3
4
  import dashboardIcon from "../../assets/icons/dashboard.svg";
4
5
  import filesIcon from "../../assets/icons/files.svg";
5
6
  import propertiesIcon from "../../assets/icons/properties.svg";
@@ -9,12 +10,14 @@ import { PATHS } from "../../lib/routeConfig";
9
10
 
10
11
  interface NavItem {
11
12
  path: string;
12
- icon: string;
13
+ /** Either an imported SVG asset URL or a lucide icon component. */
14
+ icon: string | React.ComponentType<{ className?: string }>;
13
15
  label: string;
14
16
  }
15
17
 
16
18
  const navItems: NavItem[] = [
17
19
  { path: PATHS.HOME, icon: dashboardIcon, label: "Dashboard" },
20
+ { path: PATHS.SEARCH, icon: SearchIcon, label: "Search" },
18
21
  { path: PATHS.APPLICATIONS, icon: filesIcon, label: "Applications" },
19
22
  { path: PATHS.PROPERTIES, icon: propertiesIcon, label: "Properties" },
20
23
  { path: PATHS.MAINTENANCE_REQUESTS, icon: maintenanceIcon, label: "Maintenance Requests" },
@@ -37,23 +40,30 @@ export const VerticalNav: React.FC<VerticalNavProps> = ({ isOpen = false, onClos
37
40
  };
38
41
 
39
42
  const navContent = (handleClick?: () => void) =>
40
- navItems.map((item) => (
41
- <Link
42
- key={item.path}
43
- to={item.path}
44
- onClick={handleClick}
45
- aria-current={isActive(item.path) ? "page" : undefined}
46
- className={`flex flex-col items-center justify-center gap-2 py-4 px-2 transition-colors ${
47
- isActive(item.path)
48
- ? "bg-purple-100 text-purple-700 border-l-4 border-purple-700"
49
- : "text-gray-600 hover:bg-gray-100 hover:text-gray-900"
50
- }`}
51
- title={item.label}
52
- >
53
- <img src={item.icon} alt="" className="w-6 h-6" />
54
- <span className="text-xs font-medium text-center">{item.label}</span>
55
- </Link>
56
- ));
43
+ navItems.map((item) => {
44
+ const Icon = typeof item.icon === "string" ? null : item.icon;
45
+ return (
46
+ <Link
47
+ key={item.path}
48
+ to={item.path}
49
+ onClick={handleClick}
50
+ aria-current={isActive(item.path) ? "page" : undefined}
51
+ className={`flex flex-col items-center justify-center gap-2 py-4 px-2 transition-colors ${
52
+ isActive(item.path)
53
+ ? "bg-purple-100 text-purple-700 border-l-4 border-purple-700"
54
+ : "text-gray-600 hover:bg-gray-100 hover:text-gray-900"
55
+ }`}
56
+ title={item.label}
57
+ >
58
+ {Icon ? (
59
+ <Icon className="w-6 h-6" />
60
+ ) : (
61
+ <img src={item.icon as string} alt="" className="w-6 h-6" />
62
+ )}
63
+ <span className="text-xs font-medium text-center">{item.label}</span>
64
+ </Link>
65
+ );
66
+ });
57
67
 
58
68
  return (
59
69
  <>