@salesforce/ui-bundle-template-app-react-sample-b2e 3.0.0 → 3.1.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/dist/CHANGELOG.md +9 -0
- package/dist/README.md +45 -10
- package/dist/force-app/main/default/applications/PropertyManagement.app-meta.xml +33 -0
- package/dist/force-app/main/default/data/Application__c.json +10 -10
- package/dist/force-app/main/default/data/data-plan.json +0 -6
- package/dist/force-app/main/default/objects/Application__c/fields/User__c.field-meta.xml +2 -2
- package/dist/force-app/main/default/objects/Property__c/Property__c.object-meta.xml +1 -1
- package/dist/force-app/main/default/permissionsets/Property_Management_Access.permissionset-meta.xml +76 -0
- package/dist/force-app/main/default/permissionsets/Tenant_Maintenance_Access.permissionset-meta.xml +1 -1
- package/dist/force-app/main/default/tabs/Agent__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Application__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/KPI_Snapshot__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Lease__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Maintenance_Request__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Maintenance_Worker__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Notification__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Payment__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Cost__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Feature__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Image__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Listing__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Management_Company__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Owner__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property_Sale__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Property__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/tabs/Tenant__c.tab-meta.xml +5 -0
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/applications/applications.ts +2 -14
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/applications/query/getApplications.graphql +1 -4
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/api/graphql-operations-types.ts +17547 -5747
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/alerts/status-alert.tsx +11 -8
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/ui/input.tsx +1 -1
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/pages/AccountObjectDetailPage.tsx +2 -4
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/__examples__/pages/AccountSearch.tsx +7 -15
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/NumericRangeFilter.tsx +9 -5
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/SearchFilter.tsx +5 -3
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/components/filters/TextFilter.tsx +5 -3
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/hooks/useAsyncData.ts +11 -4
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/hooks/useAsyncData.ts +67 -0
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/ApplicationSearch.tsx +6 -9
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/MaintenanceRequestSearch.tsx +5 -17
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/MaintenanceWorkerSearch.tsx +3 -8
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/PropertySearch.tsx +4 -12
- package/dist/force-app/{main/default/scripts → scripts}/org-setup.config.json +1 -1
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/dist/scripts/org-setup.config.json +0 -1
- package/dist/scripts/org-setup.mjs +528 -44
- package/package.json +2 -2
- package/dist/force-app/main/default/data/Contact.json +0 -44
- package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/features/object-search/hooks/useCachedAsyncData.ts +0 -188
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
-
import { AlertCircleIcon, CheckCircle2Icon } from 'lucide-react';
|
|
2
|
+
import { AlertCircleIcon, CheckCircle2Icon, InfoIcon } from 'lucide-react';
|
|
3
3
|
import { Alert, AlertDescription } from '../../components/ui/alert';
|
|
4
4
|
import { useId } from 'react';
|
|
5
5
|
|
|
@@ -8,6 +8,7 @@ const statusAlertVariants = cva('', {
|
|
|
8
8
|
variant: {
|
|
9
9
|
error: '',
|
|
10
10
|
success: '',
|
|
11
|
+
info: 'text-blue-600 *:[svg]:text-current *:data-[slot=alert-description]:text-blue-600/90',
|
|
11
12
|
},
|
|
12
13
|
},
|
|
13
14
|
defaultVariants: {
|
|
@@ -18,11 +19,11 @@ const statusAlertVariants = cva('', {
|
|
|
18
19
|
interface StatusAlertProps extends VariantProps<typeof statusAlertVariants> {
|
|
19
20
|
children?: React.ReactNode;
|
|
20
21
|
/** Alert variant type. @default "error" */
|
|
21
|
-
variant?: 'error' | 'success';
|
|
22
|
+
variant?: 'error' | 'success' | 'info';
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
* Status alert component for displaying error or
|
|
26
|
+
* Status alert component for displaying error, success, or info messages.
|
|
26
27
|
* Returns null if no children are provided.
|
|
27
28
|
*/
|
|
28
29
|
export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
|
|
@@ -31,6 +32,12 @@ export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
|
|
|
31
32
|
|
|
32
33
|
const isError = variant === 'error';
|
|
33
34
|
|
|
35
|
+
const icon = {
|
|
36
|
+
error: <AlertCircleIcon aria-hidden="true" />,
|
|
37
|
+
success: <CheckCircle2Icon aria-hidden="true" />,
|
|
38
|
+
info: <InfoIcon aria-hidden="true" />,
|
|
39
|
+
}[variant];
|
|
40
|
+
|
|
34
41
|
return (
|
|
35
42
|
<Alert
|
|
36
43
|
variant={isError ? 'destructive' : 'default'}
|
|
@@ -38,11 +45,7 @@ export function StatusAlert({ children, variant = 'error' }: StatusAlertProps) {
|
|
|
38
45
|
aria-describedby={descriptionId}
|
|
39
46
|
role={isError ? 'alert' : 'status'}
|
|
40
47
|
>
|
|
41
|
-
{
|
|
42
|
-
<AlertCircleIcon aria-hidden="true" />
|
|
43
|
-
) : (
|
|
44
|
-
<CheckCircle2Icon aria-hidden="true" />
|
|
45
|
-
)}
|
|
48
|
+
{icon}
|
|
46
49
|
<AlertDescription id={descriptionId}>{children}</AlertDescription>
|
|
47
50
|
</Alert>
|
|
48
51
|
);
|
package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/components/ui/input.tsx
CHANGED
|
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
|
|
8
8
|
type={type}
|
|
9
9
|
data-slot="input"
|
|
10
10
|
className={cn(
|
|
11
|
-
'dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
11
|
+
'dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground/70 placeholder:italic w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
12
12
|
className
|
|
13
13
|
)}
|
|
14
14
|
{...props}
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "../../../../components/ui/collapsible";
|
|
19
19
|
import { Separator } from "../../../../components/ui/separator";
|
|
20
20
|
import { Skeleton } from "../../../../components/ui/skeleton";
|
|
21
|
-
import {
|
|
21
|
+
import { useAsyncData } from "../../hooks/useAsyncData";
|
|
22
22
|
import { ObjectBreadcrumb } from "../../components/ObjectBreadcrumb";
|
|
23
23
|
|
|
24
24
|
type AccountNode = NonNullable<
|
|
@@ -49,9 +49,7 @@ export default function AccountObjectDetail() {
|
|
|
49
49
|
data: account,
|
|
50
50
|
loading,
|
|
51
51
|
error,
|
|
52
|
-
} =
|
|
53
|
-
key: `account:${recordId}`,
|
|
54
|
-
});
|
|
52
|
+
} = useAsyncData(() => fetchAccountDetail(recordId!), [recordId]);
|
|
55
53
|
|
|
56
54
|
return (
|
|
57
55
|
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
fetchDistinctIndustries,
|
|
7
7
|
fetchDistinctTypes,
|
|
8
8
|
} from "../api/accountSearchService";
|
|
9
|
-
import {
|
|
9
|
+
import { useAsyncData } from "../../hooks/useAsyncData";
|
|
10
10
|
import { fieldValue } from "../../utils/fieldUtils";
|
|
11
11
|
import { useObjectSearchParams } from "../../hooks/useObjectSearchParams";
|
|
12
12
|
import { Alert, AlertTitle, AlertDescription } from "../../../../components/ui/alert";
|
|
@@ -42,8 +42,8 @@ import PaginationControls from "../../components/PaginationControls";
|
|
|
42
42
|
import type { PaginationConfig } from "../../hooks/useObjectSearchParams";
|
|
43
43
|
|
|
44
44
|
const PAGINATION_CONFIG: PaginationConfig = {
|
|
45
|
-
defaultPageSize:
|
|
46
|
-
validPageSizes: [
|
|
45
|
+
defaultPageSize: 7,
|
|
46
|
+
validPageSizes: [7, 14, 28, 42],
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
type AccountNode = NonNullable<
|
|
@@ -77,22 +77,15 @@ const ACCOUNT_SORT_CONFIGS: SortFieldConfig<keyof Account_OrderBy>[] = [
|
|
|
77
77
|
|
|
78
78
|
export default function AccountSearch() {
|
|
79
79
|
const [filtersOpen, setFiltersOpen] = useState(true);
|
|
80
|
-
const { data: industryOptions } =
|
|
81
|
-
|
|
82
|
-
ttl: 300_000,
|
|
83
|
-
});
|
|
84
|
-
const { data: typeOptions } = useCachedAsyncData(fetchDistinctTypes, [], {
|
|
85
|
-
key: "distinctTypes",
|
|
86
|
-
ttl: 300_000,
|
|
87
|
-
});
|
|
80
|
+
const { data: industryOptions } = useAsyncData(fetchDistinctIndustries, []);
|
|
81
|
+
const { data: typeOptions } = useAsyncData(fetchDistinctTypes, []);
|
|
88
82
|
|
|
89
83
|
const { filters, sort, query, pagination, resetAll } = useObjectSearchParams<
|
|
90
84
|
Account_Filter,
|
|
91
85
|
Account_OrderBy
|
|
92
86
|
>(FILTER_CONFIGS, ACCOUNT_SORT_CONFIGS, PAGINATION_CONFIG);
|
|
93
87
|
|
|
94
|
-
const
|
|
95
|
-
const { data, loading, error } = useCachedAsyncData(
|
|
88
|
+
const { data, loading, error } = useAsyncData(
|
|
96
89
|
() =>
|
|
97
90
|
searchAccounts({
|
|
98
91
|
where: query.where,
|
|
@@ -101,7 +94,6 @@ export default function AccountSearch() {
|
|
|
101
94
|
after: pagination.afterCursor,
|
|
102
95
|
}),
|
|
103
96
|
[query.where, query.orderBy, pagination.pageSize, pagination.afterCursor],
|
|
104
|
-
{ key: searchKey },
|
|
105
97
|
);
|
|
106
98
|
|
|
107
99
|
const pageInfo = data?.pageInfo;
|
|
@@ -196,7 +188,7 @@ export default function AccountSearch() {
|
|
|
196
188
|
<ActiveFilters filters={filters.active} onRemove={filters.remove} />
|
|
197
189
|
</div>
|
|
198
190
|
|
|
199
|
-
<div className="min-h-
|
|
191
|
+
<div className="min-h-132">
|
|
200
192
|
{/* Loading state */}
|
|
201
193
|
{loading && (
|
|
202
194
|
<>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
import { Input } from "../../../../components/ui/input";
|
|
3
3
|
|
|
4
4
|
import { useFilterField } from "../FilterContext";
|
|
@@ -67,12 +67,16 @@ export function NumericRangeFilterInputs({
|
|
|
67
67
|
|
|
68
68
|
const externalMin = value?.min ?? "";
|
|
69
69
|
const externalMax = value?.max ?? "";
|
|
70
|
-
|
|
70
|
+
const [prevExternalMin, setPrevExternalMin] = useState(externalMin);
|
|
71
|
+
const [prevExternalMax, setPrevExternalMax] = useState(externalMax);
|
|
72
|
+
if (prevExternalMin !== externalMin) {
|
|
73
|
+
setPrevExternalMin(externalMin);
|
|
71
74
|
setLocalMin(externalMin);
|
|
72
|
-
}
|
|
73
|
-
|
|
75
|
+
}
|
|
76
|
+
if (prevExternalMax !== externalMax) {
|
|
77
|
+
setPrevExternalMax(externalMax);
|
|
74
78
|
setLocalMax(externalMax);
|
|
75
|
-
}
|
|
79
|
+
}
|
|
76
80
|
|
|
77
81
|
const isOutOfBounds = (v: string) => {
|
|
78
82
|
if (v === "") return false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { SearchBar } from "../SearchBar";
|
|
4
4
|
import { useFilterField } from "../FilterContext";
|
|
@@ -22,9 +22,11 @@ export function SearchFilter({
|
|
|
22
22
|
const [localValue, setLocalValue] = useState(value?.value ?? "");
|
|
23
23
|
|
|
24
24
|
const externalValue = value?.value ?? "";
|
|
25
|
-
|
|
25
|
+
const [prevExternalValue, setPrevExternalValue] = useState(externalValue);
|
|
26
|
+
if (prevExternalValue !== externalValue) {
|
|
27
|
+
setPrevExternalValue(externalValue);
|
|
26
28
|
setLocalValue(externalValue);
|
|
27
|
-
}
|
|
29
|
+
}
|
|
28
30
|
|
|
29
31
|
const debouncedOnChange = useDebouncedCallback((v: string) => {
|
|
30
32
|
if (v) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
import { Input } from "../../../../components/ui/input";
|
|
3
3
|
import { cn } from "../../../../lib/utils";
|
|
4
4
|
import { useFilterField } from "../FilterContext";
|
|
@@ -62,9 +62,11 @@ export function TextFilterInput({
|
|
|
62
62
|
const [localValue, setLocalValue] = useState(value?.value ?? "");
|
|
63
63
|
|
|
64
64
|
const externalValue = value?.value ?? "";
|
|
65
|
-
|
|
65
|
+
const [prevExternalValue, setPrevExternalValue] = useState(externalValue);
|
|
66
|
+
if (prevExternalValue !== externalValue) {
|
|
67
|
+
setPrevExternalValue(externalValue);
|
|
66
68
|
setLocalValue(externalValue);
|
|
67
|
-
}
|
|
69
|
+
}
|
|
68
70
|
|
|
69
71
|
const debouncedOnChange = useDebouncedCallback((v: string) => {
|
|
70
72
|
if (v) {
|
|
@@ -22,16 +22,24 @@ export function useAsyncData<T>(
|
|
|
22
22
|
const [data, setData] = useState<T | null>(null);
|
|
23
23
|
const [loading, setLoading] = useState(true);
|
|
24
24
|
const [error, setError] = useState<string | null>(null);
|
|
25
|
+
const [generation, setGeneration] = useState(0);
|
|
25
26
|
|
|
26
27
|
const fetcherRef = useRef(fetcher);
|
|
27
28
|
useEffect(() => {
|
|
28
29
|
fetcherRef.current = fetcher;
|
|
29
30
|
});
|
|
30
31
|
|
|
32
|
+
// Detect dep changes during render to reset loading state and bump generation
|
|
33
|
+
const [prevDeps, setPrevDeps] = useState(deps);
|
|
34
|
+
if (deps.length !== prevDeps.length || deps.some((d, i) => d !== prevDeps[i])) {
|
|
35
|
+
setPrevDeps(deps);
|
|
36
|
+
setGeneration((g) => g + 1);
|
|
37
|
+
if (!loading) setLoading(true);
|
|
38
|
+
if (error !== null) setError(null);
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
useEffect(() => {
|
|
32
42
|
let cancelled = false;
|
|
33
|
-
setLoading(true);
|
|
34
|
-
setError(null);
|
|
35
43
|
|
|
36
44
|
fetcherRef
|
|
37
45
|
.current()
|
|
@@ -49,8 +57,7 @@ export function useAsyncData<T>(
|
|
|
49
57
|
return () => {
|
|
50
58
|
cancelled = true;
|
|
51
59
|
};
|
|
52
|
-
|
|
53
|
-
}, deps);
|
|
60
|
+
}, [generation]);
|
|
54
61
|
|
|
55
62
|
return { data, loading, error };
|
|
56
63
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
interface UseAsyncDataResult<T> {
|
|
4
|
+
data: T | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Runs an async fetcher on mount and whenever `deps` change.
|
|
11
|
+
* Returns the loading/error/data state. Does not cache — every call
|
|
12
|
+
* to the fetcher hits the source directly.
|
|
13
|
+
*
|
|
14
|
+
* A cleanup flag prevents state updates if the component unmounts
|
|
15
|
+
* or deps change before the fetch completes (avoids React warnings
|
|
16
|
+
* and stale updates from out-of-order responses).
|
|
17
|
+
*/
|
|
18
|
+
export function useAsyncData<T>(
|
|
19
|
+
fetcher: () => Promise<T>,
|
|
20
|
+
deps: React.DependencyList
|
|
21
|
+
): UseAsyncDataResult<T> {
|
|
22
|
+
const [data, setData] = useState<T | null>(null);
|
|
23
|
+
const [loading, setLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState<string | null>(null);
|
|
25
|
+
const [generation, setGeneration] = useState(0);
|
|
26
|
+
|
|
27
|
+
const fetcherRef = useRef(fetcher);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
fetcherRef.current = fetcher;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Detect dep changes during render to reset loading state and bump generation
|
|
33
|
+
const [prevDeps, setPrevDeps] = useState(deps);
|
|
34
|
+
if (
|
|
35
|
+
deps.length !== prevDeps.length ||
|
|
36
|
+
deps.some((d, i) => d !== prevDeps[i])
|
|
37
|
+
) {
|
|
38
|
+
setPrevDeps(deps);
|
|
39
|
+
setGeneration(g => g + 1);
|
|
40
|
+
if (!loading) setLoading(true);
|
|
41
|
+
if (error !== null) setError(null);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
let cancelled = false;
|
|
46
|
+
|
|
47
|
+
fetcherRef
|
|
48
|
+
.current()
|
|
49
|
+
.then(result => {
|
|
50
|
+
if (!cancelled) setData(result);
|
|
51
|
+
})
|
|
52
|
+
.catch(err => {
|
|
53
|
+
console.error(err);
|
|
54
|
+
if (!cancelled)
|
|
55
|
+
setError(err instanceof Error ? err.message : 'An error occurred');
|
|
56
|
+
})
|
|
57
|
+
.finally(() => {
|
|
58
|
+
if (!cancelled) setLoading(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return () => {
|
|
62
|
+
cancelled = true;
|
|
63
|
+
};
|
|
64
|
+
}, [generation]);
|
|
65
|
+
|
|
66
|
+
return { data, loading, error };
|
|
67
|
+
}
|
package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/ApplicationSearch.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
searchApplications,
|
|
6
6
|
fetchDistinctApplicationStatus,
|
|
7
7
|
} from "../api/applications/applicationSearchService";
|
|
8
|
-
import {
|
|
8
|
+
import { useAsyncData } from "../hooks/useAsyncData";
|
|
9
9
|
import {
|
|
10
10
|
useObjectSearchParams,
|
|
11
11
|
type UseObjectSearchParamsReturn,
|
|
@@ -72,11 +72,9 @@ export default function ApplicationSearch() {
|
|
|
72
72
|
const [selectedApplication, setSelectedApplication] = useState<ApplicationSearchNode | null>(
|
|
73
73
|
null,
|
|
74
74
|
);
|
|
75
|
+
const [refreshKey, setRefreshKey] = useState(0);
|
|
75
76
|
|
|
76
|
-
const { data: statusOptions } =
|
|
77
|
-
key: "distinctApplicationStatus",
|
|
78
|
-
ttl: 30_000,
|
|
79
|
-
});
|
|
77
|
+
const { data: statusOptions } = useAsyncData(fetchDistinctApplicationStatus, []);
|
|
80
78
|
|
|
81
79
|
const { filters, query, pagination, resetAll } = useObjectSearchParams<
|
|
82
80
|
Application__C_Filter,
|
|
@@ -86,8 +84,7 @@ export default function ApplicationSearch() {
|
|
|
86
84
|
() => query.orderBy ?? { CreatedDate: { order: ResultOrder.Desc } },
|
|
87
85
|
[query.orderBy],
|
|
88
86
|
);
|
|
89
|
-
const
|
|
90
|
-
const { data, loading, error } = useCachedAsyncData(
|
|
87
|
+
const { data, loading, error } = useAsyncData(
|
|
91
88
|
() =>
|
|
92
89
|
searchApplications({
|
|
93
90
|
where: query.where,
|
|
@@ -95,8 +92,7 @@ export default function ApplicationSearch() {
|
|
|
95
92
|
first: pagination.pageSize,
|
|
96
93
|
after: pagination.afterCursor,
|
|
97
94
|
}),
|
|
98
|
-
[query.where, effectiveOrderBy, pagination.pageSize, pagination.afterCursor],
|
|
99
|
-
{ key: searchKey },
|
|
95
|
+
[query.where, effectiveOrderBy, pagination.pageSize, pagination.afterCursor, refreshKey],
|
|
100
96
|
);
|
|
101
97
|
|
|
102
98
|
const validApplicationNodes = useMemo(
|
|
@@ -119,6 +115,7 @@ export default function ApplicationSearch() {
|
|
|
119
115
|
if (selectedApplication?.Id === applicationId) {
|
|
120
116
|
setSelectedApplication({ ...selectedApplication, Status__c: { value: status } });
|
|
121
117
|
}
|
|
118
|
+
setRefreshKey((k) => k + 1);
|
|
122
119
|
toast.success("Status updated", {
|
|
123
120
|
description: "Application status has been updated successfully.",
|
|
124
121
|
});
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
fetchDistinctMaintenanceRequestPriority,
|
|
9
9
|
type MaintenanceRequestSearchNode,
|
|
10
10
|
} from "../api/maintenanceRequests/maintenanceRequestSearchService";
|
|
11
|
-
import {
|
|
11
|
+
import { useAsyncData } from "../hooks/useAsyncData";
|
|
12
12
|
import {
|
|
13
13
|
useObjectSearchParams,
|
|
14
14
|
type UseObjectSearchParamsReturn,
|
|
@@ -87,19 +87,9 @@ const SORT_CONFIGS: SortFieldConfig<string>[] = [
|
|
|
87
87
|
export default function MaintenanceRequestSearch() {
|
|
88
88
|
const [selectedRequest, setSelectedRequest] = useState<MaintenanceRequestSearchNode | null>(null);
|
|
89
89
|
|
|
90
|
-
const { data: statusOptions } =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
});
|
|
94
|
-
const { data: typeOptions } = useCachedAsyncData(fetchDistinctMaintenanceRequestType, [], {
|
|
95
|
-
key: "distinctMaintenanceRequestType",
|
|
96
|
-
ttl: 30_000,
|
|
97
|
-
});
|
|
98
|
-
const { data: priorityOptions } = useCachedAsyncData(
|
|
99
|
-
fetchDistinctMaintenanceRequestPriority,
|
|
100
|
-
[],
|
|
101
|
-
{ key: "distinctMaintenanceRequestPriority", ttl: 30_000 },
|
|
102
|
-
);
|
|
90
|
+
const { data: statusOptions } = useAsyncData(fetchDistinctMaintenanceRequestStatus, []);
|
|
91
|
+
const { data: typeOptions } = useAsyncData(fetchDistinctMaintenanceRequestType, []);
|
|
92
|
+
const { data: priorityOptions } = useAsyncData(fetchDistinctMaintenanceRequestPriority, []);
|
|
103
93
|
|
|
104
94
|
const { filters, query, pagination, resetAll } = useObjectSearchParams<
|
|
105
95
|
Maintenance_Request__C_Filter,
|
|
@@ -109,8 +99,7 @@ export default function MaintenanceRequestSearch() {
|
|
|
109
99
|
() => query.orderBy ?? { CreatedDate: { order: ResultOrder.Desc } },
|
|
110
100
|
[query.orderBy],
|
|
111
101
|
);
|
|
112
|
-
const
|
|
113
|
-
const { data, loading, error } = useCachedAsyncData(
|
|
102
|
+
const { data, loading, error } = useAsyncData(
|
|
114
103
|
() =>
|
|
115
104
|
searchMaintenanceRequests({
|
|
116
105
|
where: query.where,
|
|
@@ -119,7 +108,6 @@ export default function MaintenanceRequestSearch() {
|
|
|
119
108
|
after: pagination.afterCursor,
|
|
120
109
|
}),
|
|
121
110
|
[query.where, effectiveOrderBy, pagination.pageSize, pagination.afterCursor],
|
|
122
|
-
{ key: searchKey },
|
|
123
111
|
);
|
|
124
112
|
|
|
125
113
|
const validMaintenanceRequestNodes = useMemo(
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
fetchDistinctMaintenanceWorkerType,
|
|
6
6
|
type MaintenanceWorkerSearchNode,
|
|
7
7
|
} from "../api/maintenanceWorkers/maintenanceWorkerSearchService";
|
|
8
|
-
import {
|
|
8
|
+
import { useAsyncData } from "../hooks/useAsyncData";
|
|
9
9
|
import {
|
|
10
10
|
useObjectSearchParams,
|
|
11
11
|
type UseObjectSearchParamsReturn,
|
|
@@ -67,18 +67,14 @@ const SORT_CONFIGS: SortFieldConfig<string>[] = [
|
|
|
67
67
|
export default function MaintenanceWorkerSearch() {
|
|
68
68
|
const [selectedWorker, setSelectedWorker] = useState<MaintenanceWorkerSearchNode | null>(null);
|
|
69
69
|
|
|
70
|
-
const { data: typeOptions } =
|
|
71
|
-
key: "distinctMaintenanceWorkerType",
|
|
72
|
-
ttl: 30_000,
|
|
73
|
-
});
|
|
70
|
+
const { data: typeOptions } = useAsyncData(fetchDistinctMaintenanceWorkerType, []);
|
|
74
71
|
|
|
75
72
|
const { filters, query, pagination, resetAll } = useObjectSearchParams<
|
|
76
73
|
Maintenance_Worker__C_Filter,
|
|
77
74
|
Maintenance_Worker__C_OrderBy
|
|
78
75
|
>(FILTER_CONFIGS, SORT_CONFIGS, PAGINATION_CONFIG);
|
|
79
76
|
|
|
80
|
-
const
|
|
81
|
-
const { data, loading, error } = useCachedAsyncData(
|
|
77
|
+
const { data, loading, error } = useAsyncData(
|
|
82
78
|
() =>
|
|
83
79
|
searchMaintenanceWorkers({
|
|
84
80
|
where: query.where,
|
|
@@ -87,7 +83,6 @@ export default function MaintenanceWorkerSearch() {
|
|
|
87
83
|
after: pagination.afterCursor,
|
|
88
84
|
}),
|
|
89
85
|
[query.where, query.orderBy, pagination.pageSize, pagination.afterCursor],
|
|
90
|
-
{ key: searchKey },
|
|
91
86
|
);
|
|
92
87
|
|
|
93
88
|
const validMaintenanceWorkerNodes = useMemo(
|
package/dist/force-app/main/default/uiBundles/propertymanagementapp/src/pages/PropertySearch.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
fetchDistinctPropertyType,
|
|
7
7
|
type PropertySearchNode,
|
|
8
8
|
} from "../api/properties/propertySearchService";
|
|
9
|
-
import {
|
|
9
|
+
import { useAsyncData } from "../hooks/useAsyncData";
|
|
10
10
|
import {
|
|
11
11
|
useObjectSearchParams,
|
|
12
12
|
type UseObjectSearchParamsReturn,
|
|
@@ -55,22 +55,15 @@ const PROPERTY_SORT_CONFIGS: SortFieldConfig<string>[] = [
|
|
|
55
55
|
export default function PropertySearch() {
|
|
56
56
|
const [selectedProperty, setSelectedProperty] = useState<PropertySearchNode | null>(null);
|
|
57
57
|
|
|
58
|
-
const { data: statusOptions } =
|
|
59
|
-
|
|
60
|
-
ttl: 30_000,
|
|
61
|
-
});
|
|
62
|
-
const { data: typeOptions } = useCachedAsyncData(fetchDistinctPropertyType, [], {
|
|
63
|
-
key: "distinctPropertyType",
|
|
64
|
-
ttl: 30_000,
|
|
65
|
-
});
|
|
58
|
+
const { data: statusOptions } = useAsyncData(fetchDistinctPropertyStatus, []);
|
|
59
|
+
const { data: typeOptions } = useAsyncData(fetchDistinctPropertyType, []);
|
|
66
60
|
|
|
67
61
|
const { filters, query, pagination, resetAll } = useObjectSearchParams<
|
|
68
62
|
Property__C_Filter,
|
|
69
63
|
Property__C_OrderBy
|
|
70
64
|
>(FILTER_CONFIGS, PROPERTY_SORT_CONFIGS, PAGINATION_CONFIG);
|
|
71
65
|
|
|
72
|
-
const
|
|
73
|
-
const { data, loading, error } = useCachedAsyncData(
|
|
66
|
+
const { data, loading, error } = useAsyncData(
|
|
74
67
|
() =>
|
|
75
68
|
searchProperties({
|
|
76
69
|
where: query.where,
|
|
@@ -79,7 +72,6 @@ export default function PropertySearch() {
|
|
|
79
72
|
after: pagination.afterCursor,
|
|
80
73
|
}),
|
|
81
74
|
[query.where, query.orderBy, pagination.pageSize, pagination.afterCursor],
|
|
82
|
-
{ key: searchKey },
|
|
83
75
|
);
|
|
84
76
|
|
|
85
77
|
const validPropertyNodes = useMemo(
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.1.0",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@lwc/eslint-plugin-lwc": "^3.3.0",
|
package/dist/package.json
CHANGED