@salesforce/webapp-template-app-react-sample-b2x-experimental 1.116.6 → 1.116.8
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 +16 -0
- package/dist/force-app/main/default/webapplications/propertyrentalapp/eslint.config.js +13 -2
- package/dist/force-app/main/default/webapplications/propertyrentalapp/package.json +3 -3
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/components/properties/PropertyMap.tsx +2 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/authentication/context/AuthContext.tsx +1 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/authentication/hooks/useCountdownTimer.ts +1 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/authentication/pages/Profile.tsx +3 -3
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/authentication/pages/Register.tsx +1 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/authentication/sessionTimeout/SessionTimeoutValidator.tsx +12 -18
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/object-search/components/FilterContext.tsx +1 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/object-search/hooks/useObjectSearchParams.ts +10 -5
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/useGeocode.ts +4 -3
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/usePropertyListingAmenities.ts +4 -3
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/usePropertyMapMarkers.ts +17 -8
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/usePropertyPrimaryImages.ts +3 -2
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/useWeather.ts +4 -7
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/pages/Application.tsx +1 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/pages/Maintenance.tsx +2 -2
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +4 -1
- /package/dist/force-app/main/default/digitalExperienceConfigs/{propertyrentalapp1.digitalExperienceConfig → propertyrentalapp1.digitalExperienceConfig-meta.xml} +0 -0
- /package/dist/force-app/main/default/networks/{propertyrentalapp.network → propertyrentalapp.network-meta.xml} +0 -0
- /package/dist/force-app/main/default/sites/{propertyrentalapp.site → propertyrentalapp.site-meta.xml} +0 -0
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
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
|
+
## [1.116.8](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.116.7...v1.116.8) (2026-03-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.116.7](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.116.6...v1.116.7) (2026-03-27)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.116.6](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.116.5...v1.116.6) (2026-03-26)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
@@ -18,7 +18,12 @@ const schemaExists = existsSync(schemaPath);
|
|
|
18
18
|
const config = [
|
|
19
19
|
// Global ignores
|
|
20
20
|
{
|
|
21
|
-
ignores: [
|
|
21
|
+
ignores: [
|
|
22
|
+
'build/**/*',
|
|
23
|
+
'dist/**/*',
|
|
24
|
+
'coverage/**/*',
|
|
25
|
+
'src/api/graphql-operations-types.ts',
|
|
26
|
+
],
|
|
22
27
|
},
|
|
23
28
|
// Config files and build tools (first to avoid inheritance)
|
|
24
29
|
{
|
|
@@ -89,11 +94,17 @@ const config = [
|
|
|
89
94
|
'react/no-unescaped-entities': 'off',
|
|
90
95
|
'@typescript-eslint/no-unused-vars': [
|
|
91
96
|
'error',
|
|
92
|
-
{
|
|
97
|
+
{
|
|
98
|
+
argsIgnorePattern: '^_',
|
|
99
|
+
varsIgnorePattern: '^_',
|
|
100
|
+
caughtErrorsIgnorePattern: '^_',
|
|
101
|
+
ignoreRestSiblings: true,
|
|
102
|
+
},
|
|
93
103
|
],
|
|
94
104
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
95
105
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
96
106
|
'@typescript-eslint/no-explicit-any': 'off',
|
|
107
|
+
'react-hooks/set-state-in-effect': 'warn',
|
|
97
108
|
},
|
|
98
109
|
settings: {
|
|
99
110
|
react: {
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@salesforce/sdk-data": "^1.116.
|
|
19
|
-
"@salesforce/webapp-experimental": "^1.116.
|
|
18
|
+
"@salesforce/sdk-data": "^1.116.8",
|
|
19
|
+
"@salesforce/webapp-experimental": "^1.116.8",
|
|
20
20
|
"@tailwindcss/vite": "^4.1.17",
|
|
21
21
|
"class-variance-authority": "^0.7.1",
|
|
22
22
|
"clsx": "^2.1.1",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@graphql-eslint/eslint-plugin": "^4.1.0",
|
|
48
48
|
"@graphql-tools/utils": "^11.0.0",
|
|
49
49
|
"@playwright/test": "^1.49.0",
|
|
50
|
-
"@salesforce/vite-plugin-webapp-experimental": "^1.116.
|
|
50
|
+
"@salesforce/vite-plugin-webapp-experimental": "^1.116.8",
|
|
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",
|
|
@@ -63,9 +63,10 @@ interface PropertyMapProps {
|
|
|
63
63
|
|
|
64
64
|
function MapCenterUpdater({ center, zoom = 13 }: { center: [number, number]; zoom?: number }) {
|
|
65
65
|
const map = useMap() as { setView: (center: [number, number], zoom: number) => void };
|
|
66
|
+
const [lat, lng] = center;
|
|
66
67
|
useEffect(() => {
|
|
67
68
|
map.setView(center, zoom);
|
|
68
|
-
}, [map, center
|
|
69
|
+
}, [map, center, lat, lng, zoom]);
|
|
69
70
|
return null;
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -86,7 +86,7 @@ export function useAuth(): AuthContextType {
|
|
|
86
86
|
* @returns {User} The authenticated user object
|
|
87
87
|
* @throws {Error} If not used within AuthProvider or user is not authenticated
|
|
88
88
|
*/
|
|
89
|
-
export function
|
|
89
|
+
export function useUser(): User {
|
|
90
90
|
const context = useAuth();
|
|
91
91
|
if (!context.user) {
|
|
92
92
|
throw new Error("Authenticated context not established");
|
|
@@ -107,7 +107,7 @@ function formatAccessibilityAnnouncement(seconds: number): string {
|
|
|
107
107
|
// @ts-expect-error - DurationFormat is not yet in TypeScript lib
|
|
108
108
|
const formatter = new Intl.DurationFormat(navigator.language, { style: "long" });
|
|
109
109
|
return formatter.format({ minutes, seconds: secs });
|
|
110
|
-
} catch
|
|
110
|
+
} catch {
|
|
111
111
|
// Fallback to manual formatting
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -8,7 +8,7 @@ import { useAppForm } from "../hooks/form";
|
|
|
8
8
|
import { ROUTES } from "../authenticationConfig";
|
|
9
9
|
import { emailSchema } from "../authHelpers";
|
|
10
10
|
import { getErrorMessage } from "../utils/helpers";
|
|
11
|
-
import {
|
|
11
|
+
import { useUser } from "../context/AuthContext";
|
|
12
12
|
import { fetchUserProfile, updateUserProfile } from "../api/userProfileApi";
|
|
13
13
|
|
|
14
14
|
const optionalString = z
|
|
@@ -33,7 +33,7 @@ const profileSchema = z.object({
|
|
|
33
33
|
type ProfileFormValues = z.infer<typeof profileSchema>;
|
|
34
34
|
|
|
35
35
|
export default function Profile() {
|
|
36
|
-
const user =
|
|
36
|
+
const user = useUser();
|
|
37
37
|
const [profile, setProfile] = useState<ProfileFormValues | null>(null);
|
|
38
38
|
const [loadError, setLoadError] = useState<string | null>(null);
|
|
39
39
|
const [success, setSuccess] = useState(false);
|
|
@@ -104,7 +104,7 @@ export default function Profile() {
|
|
|
104
104
|
const formData = profileSchema.parse(profile);
|
|
105
105
|
form.reset(formData);
|
|
106
106
|
}
|
|
107
|
-
}, [profile]);
|
|
107
|
+
}, [profile, form]);
|
|
108
108
|
|
|
109
109
|
if (!profile && !loadError) {
|
|
110
110
|
return <CardSkeleton contentMaxWidth="md" loadingText="Loading profile…" />;
|
|
@@ -46,7 +46,7 @@ export default function Register() {
|
|
|
46
46
|
// "/services/apexrest/auth/register" refers to a custom Apex Class exposed as a REST resource.
|
|
47
47
|
// You must ensure this Apex class exists in your org and handles registration
|
|
48
48
|
// (e.g., duplicate checks and user creation such as Site.createExternalUser).
|
|
49
|
-
const { confirmPassword, ...request } = formFieldValues;
|
|
49
|
+
const { confirmPassword: _confirmPassword, ...request } = formFieldValues;
|
|
50
50
|
const sdk = await createDataSDK();
|
|
51
51
|
const response = await sdk.fetch!("/services/apexrest/auth/register", {
|
|
52
52
|
method: "POST",
|
|
@@ -496,8 +496,18 @@ export default function SessionTimeoutValidator({
|
|
|
496
496
|
// Get current location from React Router
|
|
497
497
|
const location = useLocation();
|
|
498
498
|
|
|
499
|
-
//
|
|
500
|
-
|
|
499
|
+
// Session expired alert — checked once at mount via lazy initializer.
|
|
500
|
+
// The session timeout handler triggers a hard navigation (window.location.replace),
|
|
501
|
+
// so the component always mounts fresh on the login page after expiry.
|
|
502
|
+
const [showExpiredAlert, setShowExpiredAlert] = useState(() => {
|
|
503
|
+
const isLoginPage = location.pathname === ROUTES.LOGIN.PATH;
|
|
504
|
+
const shouldShow =
|
|
505
|
+
isLoginPage && sessionStorage.getItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE) === "true";
|
|
506
|
+
if (shouldShow) {
|
|
507
|
+
sessionStorage.removeItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE);
|
|
508
|
+
}
|
|
509
|
+
return shouldShow;
|
|
510
|
+
});
|
|
501
511
|
|
|
502
512
|
// Session timeout monitoring hook
|
|
503
513
|
const sessionTimeout = useSessionTimeout({
|
|
@@ -505,22 +515,6 @@ export default function SessionTimeoutValidator({
|
|
|
505
515
|
isGuest,
|
|
506
516
|
});
|
|
507
517
|
|
|
508
|
-
/**
|
|
509
|
-
* Check if we should show expired session message
|
|
510
|
-
* Called on mount and whenever pathname changes
|
|
511
|
-
*/
|
|
512
|
-
useEffect(() => {
|
|
513
|
-
// Check if we're on the login page and should show expired message
|
|
514
|
-
const isLoginPage = location.pathname === ROUTES.LOGIN.PATH;
|
|
515
|
-
const shouldShowMessage = sessionStorage.getItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE) === "true";
|
|
516
|
-
|
|
517
|
-
if (isLoginPage && shouldShowMessage) {
|
|
518
|
-
setShowExpiredAlert(true);
|
|
519
|
-
// Clear the flag immediately after reading
|
|
520
|
-
sessionStorage.removeItem(STORAGE_KEYS.SHOW_SESSION_MESSAGE);
|
|
521
|
-
}
|
|
522
|
-
}, [location.pathname]);
|
|
523
|
-
|
|
524
518
|
/**
|
|
525
519
|
* Handle session extension
|
|
526
520
|
* Called when user clicks "Continue Working" in warning modal
|
|
@@ -60,7 +60,7 @@ export function useFilterPanel() {
|
|
|
60
60
|
return { hasActiveFilters: filters.length > 0, resetAll: onReset };
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
type FilterResetButtonProps = Omit<React.ComponentProps<typeof Button>, "onClick">;
|
|
64
64
|
|
|
65
65
|
export function FilterResetButton({ children, ...props }: FilterResetButtonProps) {
|
|
66
66
|
const { hasActiveFilters, resetAll } = useFilterPanel();
|
|
@@ -61,7 +61,10 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
61
61
|
paginationConfig?: PaginationConfig,
|
|
62
62
|
) {
|
|
63
63
|
const defaultPageSize = paginationConfig?.defaultPageSize ?? 10;
|
|
64
|
-
const validPageSizes =
|
|
64
|
+
const validPageSizes = useMemo(
|
|
65
|
+
() => paginationConfig?.validPageSizes ?? [defaultPageSize],
|
|
66
|
+
[paginationConfig?.validPageSizes, defaultPageSize],
|
|
67
|
+
);
|
|
65
68
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
66
69
|
|
|
67
70
|
// Seed local state from URL on initial load
|
|
@@ -76,8 +79,10 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
76
79
|
const [sort, setLocalSort] = useState<SortState | null>(initial.sort);
|
|
77
80
|
|
|
78
81
|
// Pagination — cursor-based with a stack to support "previous page" navigation.
|
|
79
|
-
const getValidPageSize = (
|
|
80
|
-
validPageSizes.includes(size) ? size : defaultPageSize
|
|
82
|
+
const getValidPageSize = useCallback(
|
|
83
|
+
(size: number) => (validPageSizes.includes(size) ? size : defaultPageSize),
|
|
84
|
+
[validPageSizes, defaultPageSize],
|
|
85
|
+
);
|
|
81
86
|
|
|
82
87
|
const [pageSize, setPageSizeState] = useState<number>(
|
|
83
88
|
getValidPageSize(initial.pageSize ?? defaultPageSize),
|
|
@@ -166,7 +171,7 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
166
171
|
resetPagination();
|
|
167
172
|
syncToUrl([], null, defaultPageSize, 0);
|
|
168
173
|
setPageSizeState(defaultPageSize);
|
|
169
|
-
}, [syncToUrl, resetPagination]);
|
|
174
|
+
}, [syncToUrl, resetPagination, defaultPageSize]);
|
|
170
175
|
|
|
171
176
|
// -- Pagination callbacks ---------------------------------------------------
|
|
172
177
|
// Uses a cursor stack to track visited pages. "Next" pushes the current
|
|
@@ -204,7 +209,7 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
204
209
|
resetPagination();
|
|
205
210
|
debouncedSyncRef.current(f, s, validated);
|
|
206
211
|
},
|
|
207
|
-
[resetPagination],
|
|
212
|
+
[resetPagination, getValidPageSize],
|
|
208
213
|
);
|
|
209
214
|
|
|
210
215
|
// -- Derived query objects ---------------------------------------------------
|
package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/useGeocode.ts
CHANGED
|
@@ -7,16 +7,17 @@ export function useGeocode(address: string | null | undefined): {
|
|
|
7
7
|
} {
|
|
8
8
|
const [coords, setCoords] = useState<GeocodeResult | null>(null);
|
|
9
9
|
const [loading, setLoading] = useState(false);
|
|
10
|
+
const trimmedAddress = address?.trim() ?? "";
|
|
10
11
|
|
|
11
12
|
useEffect(() => {
|
|
12
|
-
if (!
|
|
13
|
+
if (!trimmedAddress) {
|
|
13
14
|
setCoords(null);
|
|
14
15
|
setLoading(false);
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
18
|
let cancelled = false;
|
|
18
19
|
setLoading(true);
|
|
19
|
-
const normalized = address
|
|
20
|
+
const normalized = address!.replace(/\n/g, ", ").trim();
|
|
20
21
|
|
|
21
22
|
(async () => {
|
|
22
23
|
try {
|
|
@@ -42,7 +43,7 @@ export function useGeocode(address: string | null | undefined): {
|
|
|
42
43
|
return () => {
|
|
43
44
|
cancelled = true;
|
|
44
45
|
};
|
|
45
|
-
}, [
|
|
46
|
+
}, [trimmedAddress]);
|
|
46
47
|
|
|
47
48
|
return { coords, loading };
|
|
48
49
|
}
|
|
@@ -23,17 +23,18 @@ export function usePropertyListingAmenities(
|
|
|
23
23
|
const loading = idsKey !== "" && idsKey !== fetchedKey;
|
|
24
24
|
|
|
25
25
|
useEffect(() => {
|
|
26
|
-
|
|
26
|
+
const ids = idsKey === "" ? [] : idsKey.split(",");
|
|
27
|
+
if (ids.length === 0) {
|
|
27
28
|
setMap({});
|
|
28
29
|
setFetchedKey("");
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
let cancelled = false;
|
|
32
|
-
Promise.all(
|
|
33
|
+
Promise.all(ids.map((id) => fetchFeaturesByPropertyId(id)))
|
|
33
34
|
.then((featuresPerProperty) => {
|
|
34
35
|
if (cancelled) return;
|
|
35
36
|
const next: Record<string, string> = {};
|
|
36
|
-
|
|
37
|
+
ids.forEach((id, i) => {
|
|
37
38
|
const features = featuresPerProperty[i] ?? [];
|
|
38
39
|
const descriptions = features
|
|
39
40
|
.map((f) => f.description)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Fetches property addresses for the current page of results only, geocodes them in parallel,
|
|
3
3
|
* and returns map markers (one pin per property in the current window).
|
|
4
4
|
*/
|
|
5
|
-
import { useState, useEffect } from "react";
|
|
5
|
+
import { useState, useEffect, useRef } from "react";
|
|
6
6
|
import { fetchPropertyAddresses } from "@/api/properties/propertyDetailGraphQL";
|
|
7
7
|
import { geocodeAddress, getStateZipFromAddress } from "@/utils/geocode";
|
|
8
8
|
import { getPropertyIdFromRecord } from "@/hooks/usePropertyPrimaryImages";
|
|
@@ -94,19 +94,29 @@ export function usePropertyMapMarkers(results: SearchResultRecord[]): {
|
|
|
94
94
|
propertyIdToLabel.set(id, getListingName(r.record));
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
+
const idsKey = [...new Set(propertyIds)].join(",");
|
|
97
98
|
|
|
99
|
+
const resultsRef = useRef(results);
|
|
100
|
+
const labelMapRef = useRef(propertyIdToLabel);
|
|
98
101
|
useEffect(() => {
|
|
99
|
-
|
|
102
|
+
resultsRef.current = results;
|
|
103
|
+
labelMapRef.current = propertyIdToLabel;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
const uniqIds = idsKey === "" ? [] : idsKey.split(",");
|
|
108
|
+
if (uniqIds.length === 0) {
|
|
100
109
|
setMarkers([]);
|
|
101
110
|
setLoading(false);
|
|
102
111
|
return;
|
|
103
112
|
}
|
|
104
113
|
let cancelled = false;
|
|
105
114
|
setLoading(true);
|
|
106
|
-
const
|
|
115
|
+
const currentResults = resultsRef.current;
|
|
116
|
+
const currentLabels = labelMapRef.current;
|
|
107
117
|
const directMarkers: MapMarker[] = [];
|
|
108
118
|
const missingIds: string[] = [];
|
|
109
|
-
for (const r of
|
|
119
|
+
for (const r of currentResults) {
|
|
110
120
|
if (!r?.record) continue;
|
|
111
121
|
const id = getPropertyIdFromRecord(r.record);
|
|
112
122
|
if (!id || !uniqIds.includes(id)) continue;
|
|
@@ -115,7 +125,7 @@ export function usePropertyMapMarkers(results: SearchResultRecord[]): {
|
|
|
115
125
|
directMarkers.push({
|
|
116
126
|
lat: coords.lat,
|
|
117
127
|
lng: coords.lng,
|
|
118
|
-
label:
|
|
128
|
+
label: currentLabels.get(id) ?? "Property",
|
|
119
129
|
propertyId: id,
|
|
120
130
|
});
|
|
121
131
|
}
|
|
@@ -140,7 +150,6 @@ export function usePropertyMapMarkers(results: SearchResultRecord[]): {
|
|
|
140
150
|
setLoading(false);
|
|
141
151
|
return;
|
|
142
152
|
}
|
|
143
|
-
// Geocode all addresses in parallel; fallback to City, State Zip if full address fails
|
|
144
153
|
Promise.all(
|
|
145
154
|
toGeocode.map(async ([id, address]) => {
|
|
146
155
|
const normalized = address.replace(/\n/g, ", ").trim();
|
|
@@ -161,7 +170,7 @@ export function usePropertyMapMarkers(results: SearchResultRecord[]): {
|
|
|
161
170
|
.map(({ id, coords }) => ({
|
|
162
171
|
lat: coords.lat,
|
|
163
172
|
lng: coords.lng,
|
|
164
|
-
label:
|
|
173
|
+
label: currentLabels.get(id) ?? "Property",
|
|
165
174
|
propertyId: id,
|
|
166
175
|
}));
|
|
167
176
|
setMarkers(spreadDuplicateMarkers([...directMarkers, ...geocoded]));
|
|
@@ -182,7 +191,7 @@ export function usePropertyMapMarkers(results: SearchResultRecord[]): {
|
|
|
182
191
|
return () => {
|
|
183
192
|
cancelled = true;
|
|
184
193
|
};
|
|
185
|
-
}, [
|
|
194
|
+
}, [idsKey]);
|
|
186
195
|
|
|
187
196
|
return { markers, loading };
|
|
188
197
|
}
|
|
@@ -28,13 +28,14 @@ export function usePropertyPrimaryImages(
|
|
|
28
28
|
const loading = idsKey !== "" && idsKey !== fetchedKey;
|
|
29
29
|
|
|
30
30
|
useEffect(() => {
|
|
31
|
-
|
|
31
|
+
const ids = idsKey === "" ? [] : idsKey.split(",");
|
|
32
|
+
if (ids.length === 0) {
|
|
32
33
|
setMap({});
|
|
33
34
|
setFetchedKey("");
|
|
34
35
|
return;
|
|
35
36
|
}
|
|
36
37
|
let cancelled = false;
|
|
37
|
-
fetchPrimaryImagesByPropertyIds(
|
|
38
|
+
fetchPrimaryImagesByPropertyIds(ids)
|
|
38
39
|
.then((next) => {
|
|
39
40
|
if (!cancelled) setMap(next);
|
|
40
41
|
})
|
package/dist/force-app/main/default/webapplications/propertyrentalapp/src/hooks/useWeather.ts
CHANGED
|
@@ -268,17 +268,14 @@ interface GeoPosition {
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
function useGeolocation(): GeoPosition {
|
|
271
|
-
const [position, setPosition] = useState<GeoPosition>({
|
|
271
|
+
const [position, setPosition] = useState<GeoPosition>(() => ({
|
|
272
272
|
latitude: FALLBACK.LAT,
|
|
273
273
|
longitude: FALLBACK.LNG,
|
|
274
|
-
resolved:
|
|
275
|
-
});
|
|
274
|
+
resolved: typeof navigator === "undefined" || !navigator.geolocation,
|
|
275
|
+
}));
|
|
276
276
|
|
|
277
277
|
useEffect(() => {
|
|
278
|
-
if (!navigator.geolocation)
|
|
279
|
-
setPosition((prev) => ({ ...prev, resolved: true }));
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
278
|
+
if (!navigator.geolocation) return;
|
|
282
279
|
navigator.geolocation.getCurrentPosition(
|
|
283
280
|
(pos) =>
|
|
284
281
|
setPosition({
|
package/dist/force-app/main/default/webapplications/propertyrentalapp/src/pages/Maintenance.tsx
CHANGED
|
@@ -75,8 +75,6 @@ export default function Maintenance() {
|
|
|
75
75
|
const [submitError, setSubmitError] = useState<string | null>(null);
|
|
76
76
|
const [submitSuccess, setSubmitSuccess] = useState(false);
|
|
77
77
|
|
|
78
|
-
if (authLoading) return <MaintenanceSkeleton />;
|
|
79
|
-
|
|
80
78
|
const handleSubmit = useCallback(
|
|
81
79
|
async (e: React.FormEvent) => {
|
|
82
80
|
e.preventDefault();
|
|
@@ -113,6 +111,8 @@ export default function Maintenance() {
|
|
|
113
111
|
[title, description, type, priority, dateRequested, refetch],
|
|
114
112
|
);
|
|
115
113
|
|
|
114
|
+
if (authLoading) return <MaintenanceSkeleton />;
|
|
115
|
+
|
|
116
116
|
return (
|
|
117
117
|
<div className="mx-auto max-w-[900px]">
|
|
118
118
|
<Card className="mb-6 rounded-2xl shadow-md">
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
3
|
-
"version": "1.116.
|
|
3
|
+
"version": "1.116.8",
|
|
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": "1.116.
|
|
9
|
+
"version": "1.116.8",
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-app-react-sample-b2x-experimental",
|
|
3
|
-
"version": "1.116.
|
|
3
|
+
"version": "1.116.8",
|
|
4
4
|
"description": "Salesforce sample property rental React app",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "",
|
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
"watch": {
|
|
33
33
|
"executor": "@salesforce/webapp-template-cli-experimental:watch-patches"
|
|
34
34
|
},
|
|
35
|
+
"build:dist-app": {
|
|
36
|
+
"executor": "@salesforce/webapp-template-cli-experimental:build-dist-app"
|
|
37
|
+
},
|
|
35
38
|
"dev": {
|
|
36
39
|
"executor": "@salesforce/webapp-template-cli-experimental:dev-server"
|
|
37
40
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|