@salesforce/webapp-template-app-react-sample-b2x-experimental 1.84.1 → 1.85.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 +8 -0
- package/dist/README.md +24 -0
- package/dist/force-app/main/default/data/Property_Image__c.json +1 -1
- package/dist/force-app/main/default/data/Property_Listing__c.json +1 -1
- package/dist/force-app/main/default/data/prepare-import-unique-fields.js +85 -0
- package/dist/force-app/main/default/permissionsets/Property_Management_Access.permissionset-meta.xml +0 -7
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/index.html +6 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/package.json +3 -3
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/applicationApi.ts +9 -9
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/graphql-operations-types.ts +296 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/graphqlClient.ts +12 -7
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/maintenanceRequestApi.ts +50 -38
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/propertyDetailGraphQL.ts +50 -102
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/propertyListingGraphQL.ts +211 -43
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/api/userApi.ts +43 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/appLayout.tsx +9 -208
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/appliances.svg +13 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/electrical.svg +39 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/hvac.svg +78 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/pest.svg +5 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/plumbing.svg +7 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/zen-logo.svg +5 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/MaintenanceRequestIcon.tsx +46 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/NavMenu.tsx +53 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/PropertyListingCard.tsx +55 -58
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/PropertyMap.tsx +93 -11
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/PropertySearchFilters.tsx +315 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/StatusBadge.tsx +36 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/TopBar.tsx +107 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/hooks/usePropertyAddresses.ts +2 -2
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/hooks/usePropertyListingAmenities.ts +55 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/hooks/usePropertyListingPriceRange.ts +64 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/hooks/usePropertyListingSearch.ts +14 -5
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/hooks/usePropertyMapMarkers.ts +54 -11
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/hooks/usePropertyPrimaryImages.ts +1 -1
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/Application.tsx +42 -39
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/Contact.tsx +10 -10
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/Dashboard.tsx +64 -91
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/HelpCenter.tsx +1 -1
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/Home.tsx +19 -9
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/Maintenance.tsx +79 -100
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/NotFound.tsx +1 -1
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/PropertyDetails.tsx +62 -47
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/PropertyListings.tsx +3 -3
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/pages/PropertySearch.tsx +230 -34
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/routes.tsx +10 -1
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/styles/global.css +64 -0
- package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/utils/geocode.ts +30 -5
- package/dist/package.json +1 -1
- package/dist/setup-cli.mjs +271 -0
- package/package.json +1 -1
package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/hvac.svg
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
3
|
+
<svg fill="currentColor" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve">
|
|
4
|
+
<g>
|
|
5
|
+
<g>
|
|
6
|
+
<path d="M482.815,93.937H29.185C13.093,93.937,0,107.029,0,123.123v265.755c0,16.093,13.093,29.186,29.185,29.186h453.63
|
|
7
|
+
c16.092,0,29.185-13.093,29.185-29.186V123.123C512,107.029,498.907,93.937,482.815,93.937z M482.815,397.665H29.185
|
|
8
|
+
c-4.845,0-8.787-3.942-8.787-8.788V123.123c0-4.845,3.942-8.788,8.787-8.788h453.63c4.845,0,8.787,3.942,8.787,8.788v265.755h0
|
|
9
|
+
C491.602,393.722,487.66,397.665,482.815,397.665z"/>
|
|
10
|
+
</g>
|
|
11
|
+
</g>
|
|
12
|
+
<g>
|
|
13
|
+
<g>
|
|
14
|
+
<path d="M165.227,138.709c-64.674,0-117.291,52.617-117.291,117.291s52.617,117.291,117.291,117.291S282.518,320.674,282.518,256
|
|
15
|
+
S229.901,138.709,165.227,138.709z M165.227,352.892c-53.427,0-96.892-43.466-96.892-96.892c0-53.426,43.466-96.892,96.892-96.892
|
|
16
|
+
c53.426,0,96.892,43.466,96.892,96.892C262.12,309.427,218.654,352.892,165.227,352.892z"/>
|
|
17
|
+
</g>
|
|
18
|
+
</g>
|
|
19
|
+
<g>
|
|
20
|
+
<g>
|
|
21
|
+
<path d="M252.137,262.786c-4.959-7.802-13.735-11.878-22.893-10.65c-11.264,1.517-22.867,0.816-33.891-2.002
|
|
22
|
+
c-1.243-5.677-4.005-10.79-7.84-14.892c1.022-2.523,2.468-4.881,4.257-6.924c7.147-8.16,11.081-18.629,11.081-29.475
|
|
23
|
+
c0-16.945-13.258-30.862-30.184-31.684l-24.291-1.179c-9.244-0.453-17.627,4.364-21.904,12.56
|
|
24
|
+
c-4.276,8.196-3.424,17.833,2.224,25.151c6.784,8.789,11.772,18.574,14.875,29.144c-4.704,4.049-8.212,9.444-9.922,15.585
|
|
25
|
+
c-2.285,0.198-4.6,0.078-6.844-0.367c-10.64-2.107-21.672-0.283-31.066,5.141c-14.675,8.472-20.099,26.913-12.347,41.981
|
|
26
|
+
l11.124,21.627c4.07,7.911,11.968,12.71,20.788,12.71c0.346,0,0.694-0.007,1.041-0.021c9.236-0.395,17.155-5.951,20.67-14.502
|
|
27
|
+
c4.25-10.345,10.288-19.619,17.974-27.634c2.942,0.902,6.063,1.389,9.298,1.389c2.924,0,5.754-0.405,8.446-1.147
|
|
28
|
+
c1.567,2.072,2.812,4.394,3.646,6.848c3.495,10.269,10.593,18.911,19.985,24.333c4.998,2.885,10.461,4.264,15.855,4.264
|
|
29
|
+
c10.443,0,20.627-5.167,26.675-14.561l13.167-20.447C257.068,280.262,257.096,270.587,252.137,262.786z M118.148,307.238
|
|
30
|
+
c-0.608,1.481-1.788,1.836-2.67,1.874c-0.882,0.035-2.089-0.215-2.821-1.639l-11.124-21.626
|
|
31
|
+
c-2.767-5.379-0.83-11.962,4.407-14.986c5.111-2.951,11.115-3.943,16.901-2.798c3.914,0.775,7.946,1.007,11.937,0.719
|
|
32
|
+
c0.934,2.318,2.133,4.501,3.56,6.513C129.792,284.674,123.018,295.385,118.148,307.238z M164.289,268.347
|
|
33
|
+
c-6.29,0-11.408-5.118-11.408-11.408s5.118-11.407,11.408-11.407s11.407,5.117,11.407,11.407S170.579,268.347,164.289,268.347z
|
|
34
|
+
M176.422,214.879c-2.8,3.198-5.136,6.819-6.93,10.688c-1.694-0.28-3.431-0.432-5.204-0.432c-0.578,0-1.151,0.017-1.723,0.048
|
|
35
|
+
c-3.845-12.279-9.783-23.67-17.721-33.954c-0.978-1.267-0.697-2.466-0.288-3.25c0.409-0.784,1.206-1.696,2.829-1.623l24.291,1.179
|
|
36
|
+
c6.042,0.294,10.774,5.261,10.774,11.309C182.452,204.744,180.31,210.439,176.422,214.879z M234.912,276.991l-13.168,20.448
|
|
37
|
+
c-3.273,5.085-9.942,6.699-15.181,3.676c-5.111-2.951-8.972-7.652-10.873-13.239c-1.421-4.174-3.49-8.141-6.072-11.73
|
|
38
|
+
c1.318-1.734,2.462-3.605,3.407-5.59c12.734,2.905,26.019,3.537,38.94,1.798c1.581-0.216,2.482,0.627,2.957,1.374
|
|
39
|
+
C235.396,274.474,235.779,275.645,234.912,276.991z"/>
|
|
40
|
+
</g>
|
|
41
|
+
</g>
|
|
42
|
+
<g>
|
|
43
|
+
<g>
|
|
44
|
+
<path d="M456.924,141.769H321.275c-5.632,0-10.199,4.566-10.199,10.199s4.567,10.199,10.199,10.199h135.649
|
|
45
|
+
c5.632,0,10.199-4.566,10.199-10.199S462.556,141.769,456.924,141.769z"/>
|
|
46
|
+
</g>
|
|
47
|
+
</g>
|
|
48
|
+
<g>
|
|
49
|
+
<g>
|
|
50
|
+
<path d="M456.924,193.785H321.275c-5.632,0-10.199,4.566-10.199,10.199s4.567,10.199,10.199,10.199h135.649
|
|
51
|
+
c5.632,0,10.199-4.566,10.199-10.199S462.556,193.785,456.924,193.785z"/>
|
|
52
|
+
</g>
|
|
53
|
+
</g>
|
|
54
|
+
<g>
|
|
55
|
+
<g>
|
|
56
|
+
<path d="M456.924,245.801H321.275c-5.632,0-10.199,4.566-10.199,10.199c0,5.633,4.567,10.199,10.199,10.199h135.649
|
|
57
|
+
c5.632,0,10.199-4.566,10.199-10.199C467.124,250.367,462.556,245.801,456.924,245.801z"/>
|
|
58
|
+
</g>
|
|
59
|
+
</g>
|
|
60
|
+
<g>
|
|
61
|
+
<g>
|
|
62
|
+
<path d="M456.924,297.817H321.275c-5.632,0-10.199,4.566-10.199,10.199c0,5.633,4.567,10.199,10.199,10.199h135.649
|
|
63
|
+
c5.632,0,10.199-4.566,10.199-10.199C467.124,302.383,462.556,297.817,456.924,297.817z"/>
|
|
64
|
+
</g>
|
|
65
|
+
</g>
|
|
66
|
+
<g>
|
|
67
|
+
<g>
|
|
68
|
+
<path d="M416.128,349.833h-94.853c-5.632,0-10.199,4.566-10.199,10.199c0,5.633,4.567,10.199,10.199,10.199h94.853
|
|
69
|
+
c5.632,0,10.199-4.566,10.199-10.199C426.327,354.399,421.76,349.833,416.128,349.833z"/>
|
|
70
|
+
</g>
|
|
71
|
+
</g>
|
|
72
|
+
<g>
|
|
73
|
+
<g>
|
|
74
|
+
<path d="M456.924,349.833h-5.1c-5.632,0-10.199,4.566-10.199,10.199c0,5.633,4.567,10.199,10.199,10.199h5.1
|
|
75
|
+
c5.632,0,10.199-4.566,10.199-10.199C467.124,354.399,462.556,349.833,456.924,349.833z"/>
|
|
76
|
+
</g>
|
|
77
|
+
</g>
|
|
78
|
+
</svg>
|
package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/pest.svg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<?xml version='1.0' encoding='iso-8859-1'?>
|
|
2
|
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
3
|
+
<svg fill="currentColor" height="800px" width="800px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 463" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 463 463">
|
|
4
|
+
<path d="m355.256,145.405c-34.083-19.724-60.085-50.573-73.704-87.254 4.229-2.018 8.958-3.151 13.947-3.151h15.971c0.008,0 0.015,0.002 0.023,0.002 0.051,0 0.102-0.008 0.153-0.009 0.234-0.005 0.465-0.017 0.693-0.042 0.079-0.009 0.157-0.025 0.236-0.036 0.216-0.031 0.43-0.07 0.639-0.119 0.034-0.008 0.069-0.011 0.103-0.019l25.941-6.485c6.912-1.729 11.74-7.912 11.74-15.037v-11.509c0-7.125-4.828-13.309-11.741-15.037l-25.94-6.485c-0.04-0.01-0.081-0.014-0.121-0.024-0.146-0.034-0.293-0.062-0.442-0.087-0.11-0.019-0.221-0.037-0.331-0.051-0.124-0.015-0.25-0.026-0.376-0.035-0.136-0.01-0.271-0.018-0.406-0.021-0.047,2.45463e-15-0.093-0.006-0.142-0.006h-98.745c-10.551,0-20.471,4.109-27.931,11.569l-56.97,56.971c-4.449,4.449-5.768,11.079-3.36,16.892s8.028,9.568 14.32,9.568h29.187v9h-0.5c-8.547,0-15.5,6.953-15.5,15.5v22.273c0,10.239-2.784,20.291-8.052,29.069l-20.639,34.398c-12.632,21.054-19.31,45.161-19.31,69.714v132.546c0,30.603 24.897,55.5 55.5,55.5h96c30.603,0 55.5-24.897 55.5-55.5v-132.546c0-24.553-6.677-48.66-19.31-69.714l-20.639-34.398c-5.268-8.778-8.052-18.83-8.052-29.069v-22.273c0-8.547-6.953-15.5-15.5-15.5h-0.5v-9h8.5c4.142,0 7.5-3.358 7.5-7.5 0-7.219 2.369-13.893 6.365-19.292 15.273,37.82 42.778,69.577 78.378,90.18 1.183,0.685 2.475,1.01 3.75,1.01 2.589,0 5.108-1.343 6.498-3.745 2.076-3.586 0.852-8.174-2.733-10.248zm-19.257-123.659v11.508c0,0.23-0.156,0.43-0.378,0.485l-16.622,4.155v-20.788l16.621,4.155c0.224,0.055 0.379,0.255 0.379,0.485zm-199.828,191.212l20.639-34.398c5.073-8.455 8.32-17.844 9.585-27.56h33.604v144.037c-1.835-0.565-3.396-1.343-5.197-2.244-4.268-2.135-9.579-4.792-19.346-4.792-9.765,0-15.076,2.658-19.343,4.793-3.721,1.862-6.409,3.207-12.631,3.207-6.225,0-8.914-1.345-12.636-3.208-3.02-1.511-6.572-3.279-11.847-4.186v-13.652c-4.26326e-14-21.836 5.938-43.274 17.172-61.997zm71.328,186.042c4.687,0 8.5,3.813 8.5,8.5v8.5h-17v-8.5c0-4.687 3.813-8.5 8.5-8.5zm48,49h-96c-22.332,0-40.5-18.168-40.5-40.5v-103.517c1.808,0.564 3.356,1.334 5.136,2.225 4.268,2.135 9.58,4.792 19.347,4.792 9.766,0 15.076-2.658 19.344-4.793 3.721-1.862 6.409-3.207 12.63-3.207 6.224,0 8.912,1.345 12.634,3.208 3.032,1.517 6.6,3.293 11.909,4.196v73.096c0,0.575 0.071,1.132 0.193,1.669-9.39,3.081-16.193,11.924-16.193,22.331v16c0,4.142 3.358,7.5 7.5,7.5h32c4.142,0 7.5-3.358 7.5-7.5v-16c0-10.407-6.803-19.25-16.193-22.331 0.122-0.537 0.193-1.094 0.193-1.669v-73.117c5.241-0.91 8.776-2.671 11.785-4.176 3.723-1.862 6.413-3.208 12.639-3.208 6.241,0 8.937,1.346 12.668,3.21 4.273,2.134 9.592,4.79 19.37,4.79s15.097-2.656 19.371-4.79c1.791-0.895 3.347-1.668 5.168-2.233v103.524c-0.001,22.332-18.169,40.5-40.501,40.5zm23.329-235.042c11.234,18.724 17.172,40.162 17.172,61.997v13.65c-5.286,0.906-8.844,2.674-11.87,4.185-3.731,1.864-6.427,3.21-12.668,3.21-6.241,0-8.937-1.346-12.668-3.21-4.273-2.134-9.592-4.79-19.37-4.79-9.768,0-15.081,2.657-19.349,4.792-1.76,0.881-3.293,1.643-5.074,2.205v-143.997h33.604c1.265,9.715 4.512,19.104 9.585,27.56l20.638,34.398zm-30.829-93.458v16.5h-81v-16.5c0-0.276 0.224-0.5 0.5-0.5h80c0.276,0 0.5,0.224 0.5,0.5zm-16-15.5h-49v-9h49v9zm16.592-24h-109.778c-0.179,0-0.334,0-0.462-0.309-0.127-0.309-0.018-0.418 0.108-0.545l56.971-56.971c4.628-4.627 10.78-7.175 17.324-7.175h91.245v25h-8.5c-23.64,0-43.302,17.359-46.908,40z"/>
|
|
5
|
+
</svg>
|
package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/plumbing.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version='1.0' encoding='iso-8859-1'?>
|
|
2
|
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
3
|
+
<svg fill="currentColor" height="800px" width="800px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 463 463" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 463 463">
|
|
4
|
+
<g>
|
|
5
|
+
<path d="m447,341.234v-17.734c0-79.126-64.374-143.5-143.5-143.5h-113.734c-3.138-9.29-11.93-16-22.266-16-4.687,0-8.5-3.813-8.5-8.5v-8.5h0.5c4.142,0 7.5-3.358 7.5-7.5s-3.358-7.5-7.5-7.5h-16.5v-27.077l47.496,9.543c1.786,0.357 3.582,0.533 5.365,0.533 6.219,0 12.28-2.137 17.192-6.165 6.321-5.182 9.947-12.842 9.947-21.016s-3.625-15.833-9.946-21.016c-6.322-5.183-14.544-7.236-22.558-5.632l-50.889,10.177c-4.123-6.796-11.593-11.347-20.107-11.347s-15.984,4.551-20.107,11.348l-50.889-10.178c-8.013-1.602-16.237,0.45-22.558,5.632-6.321,5.182-9.946,12.842-9.946,21.016s3.625,15.834 9.947,21.016c4.913,4.028 10.975,6.166 17.192,6.166 1.781,0 3.575-0.176 5.357-0.532l47.504-9.443v26.975h-16.5c-4.142,0-7.5,3.358-7.5,7.5s3.358,7.5 7.5,7.5h0.5v8.5c0,4.687-3.813,8.5-8.5,8.5-10.336,0-19.128,6.71-22.266,16h-25.734c-12.958,0-23.5,10.542-23.5,23.5v64c0,12.958 10.542,23.5 23.5,23.5h25.734c3.138,9.29 11.93,16 22.266,16h96c10.336,0 19.128-6.71 22.266-16h113.734c17.92,0 32.5,14.58 32.5,32.5v17.734c-9.29,3.138-16,11.93-16,22.266v16c0,12.958 10.542,23.5 23.5,23.5h96c12.958,0 23.5-10.542 23.5-23.5v-16c0-10.336-6.71-19.128-16-22.266zm-253.563-265.355c3.589-0.719 7.274,0.201 10.107,2.523 2.832,2.322 4.456,5.753 4.456,9.416s-1.625,7.094-4.457,9.416c-2.832,2.322-6.516,3.242-10.1,2.524l-50.443-10.135v-3.657l50.437-10.087zm-73.937-.879c4.687,0 8.5,3.813 8.5,8.5v16.5h-17v-16.5c0-4.687 3.813-8.5 8.5-8.5zm-73.937,24.757c-3.592,0.719-7.275-0.202-10.106-2.523-2.832-2.322-4.457-5.754-4.457-9.416s1.624-7.094 4.456-9.416c2.832-2.322 6.515-3.243 10.107-2.523l50.437,10.088v3.765l-50.437,10.025zm65.437,15.243h17v17h-17v-17zm-96,152.5v-64c0-4.687 3.813-8.5 8.5-8.5h24.5v81h-24.5c-4.687,0-8.5-3.813-8.5-8.5zm161,16c0,4.687-3.813,8.5-8.5,8.5h-96c-4.68,0-8.488-3.803-8.499-8.481 0-0.007 0.001-0.013 0.001-0.019 0-0.013-0.002-0.026-0.002-0.039v-95.923c0-0.013 0.002-0.026 0.002-0.039 0-0.007-0.001-0.013-0.001-0.019 0.011-4.677 3.819-8.48 8.499-8.48 12.958,0 23.5-10.542 23.5-23.5v-8.5h49v8.5c0,12.958 10.542,23.5 23.5,23.5 4.687,0 8.5,3.813 8.5,8.5v96zm127.5-7.5h-112.5v-81h112.5c70.855,0 128.5,57.645 128.5,128.5v16.5h-81v-16.5c0-26.191-21.309-47.5-47.5-47.5zm144.5,103.5c0,4.687-3.813,8.5-8.5,8.5h-96c-4.687,0-8.5-3.813-8.5-8.5v-16c0-4.687 3.813-8.5 8.5-8.5h96c4.687,0 8.5,3.813 8.5,8.5v16z"/>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/assets/icons/zen-logo.svg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="40" height="40" rx="8" fill="black" fill-opacity="0.2"/>
|
|
3
|
+
<path d="M10 31V16.3333C13.4868 16.6744 19.9209 18.0046 20.3194 20.5969C20.4604 21.5144 20.45 31 20.45 31M13.4972 31L13.7641 13.9457C13.7641 10.1 25.95 9 25.95 9V31" stroke="white" stroke-width="1.5"/>
|
|
4
|
+
<path d="M29.2494 31.0001V23.4681C25.2137 22.8637 21.6875 23.9923 19.3778 25.2149C18.3982 25.7334 17.6374 26.2688 17.1494 26.6961V31.0001" stroke="white" stroke-width="1.5"/>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a type-specific icon for maintenance requests (same approach as b2e MaintenanceTable).
|
|
3
|
+
* Uses imported SVG assets; fallback to 🔧 when type has no icon.
|
|
4
|
+
*/
|
|
5
|
+
import PlumbingIcon from "@/assets/icons/plumbing.svg";
|
|
6
|
+
import HVACIcon from "@/assets/icons/hvac.svg";
|
|
7
|
+
import ElectricalIcon from "@/assets/icons/electrical.svg";
|
|
8
|
+
import AppliancesIcon from "@/assets/icons/appliances.svg";
|
|
9
|
+
import PestIcon from "@/assets/icons/pest.svg";
|
|
10
|
+
|
|
11
|
+
const issueIcons: Record<string, string> = {
|
|
12
|
+
Plumbing: PlumbingIcon,
|
|
13
|
+
HVAC: HVACIcon,
|
|
14
|
+
Electrical: ElectricalIcon,
|
|
15
|
+
Appliance: AppliancesIcon,
|
|
16
|
+
Pest: PestIcon,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const issueIconColors: Record<string, string> = {
|
|
20
|
+
Plumbing: "bg-teal-100",
|
|
21
|
+
HVAC: "bg-teal-100",
|
|
22
|
+
Electrical: "bg-teal-100",
|
|
23
|
+
Appliance: "bg-teal-100",
|
|
24
|
+
Pest: "bg-teal-100",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function MaintenanceRequestIcon({ type }: { type: string | null }) {
|
|
28
|
+
const issueType = type?.trim() ?? "";
|
|
29
|
+
const iconSrc = issueIcons[issueType];
|
|
30
|
+
const bgClass = issueIconColors[issueType] ?? "bg-teal-100";
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
className={`flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-lg ${bgClass}`}
|
|
35
|
+
aria-hidden
|
|
36
|
+
>
|
|
37
|
+
{iconSrc ? (
|
|
38
|
+
<img src={iconSrc} alt={issueType || "Request"} className="h-6 w-6" />
|
|
39
|
+
) : (
|
|
40
|
+
<span className="text-2xl" aria-hidden>
|
|
41
|
+
🔧
|
|
42
|
+
</span>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/NavMenu.tsx
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Link, useLocation } from "react-router";
|
|
2
|
+
import { Home, Search, BarChart3, Wrench, Phone, type LucideIcon } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
interface NavItem {
|
|
5
|
+
path: string;
|
|
6
|
+
icon: LucideIcon;
|
|
7
|
+
label: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const navItems: NavItem[] = [
|
|
11
|
+
{ path: "/", icon: Home, label: "Home" },
|
|
12
|
+
{ path: "/dashboard", icon: BarChart3, label: "Dashboard" },
|
|
13
|
+
{ path: "/properties", icon: Search, label: "Property Search" },
|
|
14
|
+
{ path: "/maintenance/requests", icon: Wrench, label: "Maintenance Requests" },
|
|
15
|
+
{ path: "/contact", icon: Phone, label: "Contact Us" },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export function NavMenu() {
|
|
19
|
+
const location = useLocation();
|
|
20
|
+
|
|
21
|
+
const isActive = (path: string) => {
|
|
22
|
+
if (path === "/") return location.pathname === "/";
|
|
23
|
+
return location.pathname.startsWith(path);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<nav
|
|
28
|
+
className="flex w-24 flex-col border-r border-gray-200 bg-white py-8"
|
|
29
|
+
aria-label="Main navigation"
|
|
30
|
+
>
|
|
31
|
+
{navItems.map((item) => {
|
|
32
|
+
const Icon = item.icon;
|
|
33
|
+
const active = isActive(item.path);
|
|
34
|
+
return (
|
|
35
|
+
<Link
|
|
36
|
+
key={item.path}
|
|
37
|
+
to={item.path}
|
|
38
|
+
className={`flex flex-col items-center justify-center gap-2 px-2 py-4 transition-colors ${
|
|
39
|
+
active
|
|
40
|
+
? "border-l-4 border-teal-700 bg-teal-100 text-teal-700"
|
|
41
|
+
: "text-gray-600 hover:bg-gray-100 hover:text-gray-900"
|
|
42
|
+
}`}
|
|
43
|
+
title={item.label}
|
|
44
|
+
aria-label={item.label}
|
|
45
|
+
>
|
|
46
|
+
<Icon className="size-6 shrink-0" aria-hidden />
|
|
47
|
+
<span className="text-center text-xs font-medium leading-tight">{item.label}</span>
|
|
48
|
+
</Link>
|
|
49
|
+
);
|
|
50
|
+
})}
|
|
51
|
+
</nav>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Stacked property listing card: image on top, details below. Single price + bedrooms, amenity list, Apply button.
|
|
3
|
+
* No phone or secondary price. Virtual Tours / Videos pills on image.
|
|
3
4
|
*/
|
|
4
5
|
import { useNavigate } from "react-router";
|
|
5
|
-
import { useCallback,
|
|
6
|
-
import { Button } from "
|
|
7
|
-
import type { SearchResultRecordData } from "
|
|
8
|
-
import { Heart } from "lucide-react";
|
|
6
|
+
import { useCallback, type MouseEvent } from "react";
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
|
+
import type { SearchResultRecordData } from "@/features/global-search/types/search/searchResults.js";
|
|
9
9
|
|
|
10
10
|
function fieldDisplay(
|
|
11
11
|
fields: Record<string, { value?: unknown; displayValue?: string | null }> | undefined,
|
|
@@ -36,18 +36,26 @@ interface PropertyListingCardProps {
|
|
|
36
36
|
imageUrl: string | null;
|
|
37
37
|
/** Property address (Address__c from Property__c) when available */
|
|
38
38
|
address?: string | null;
|
|
39
|
+
/** Amenities string (e.g. "In-unit washer | Pool | Gym"), separated by | */
|
|
40
|
+
amenities?: string | null;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export default function PropertyListingCard({
|
|
42
44
|
record,
|
|
43
45
|
imageUrl,
|
|
44
46
|
address,
|
|
47
|
+
amenities,
|
|
45
48
|
}: PropertyListingCardProps) {
|
|
46
49
|
const navigate = useNavigate();
|
|
47
|
-
const [favorited, setFavorited] = useState(false);
|
|
48
50
|
const name = fieldDisplay(record.fields, "Name") ?? "Untitled";
|
|
49
51
|
const price = fieldDisplay(record.fields, "Listing_Price__c");
|
|
50
52
|
const propertyRef = fieldDisplay(record.fields, "Property__c");
|
|
53
|
+
const bedroomsRaw = fieldDisplay(record.fields, "Property__r.Bedrooms__c");
|
|
54
|
+
const bedroomsNum = bedroomsRaw != null && bedroomsRaw !== "" ? Number(bedroomsRaw) : NaN;
|
|
55
|
+
const bedroomsLabel =
|
|
56
|
+
!Number.isNaN(bedroomsNum) && bedroomsNum >= 0
|
|
57
|
+
? `${bedroomsNum} Bedroom${bedroomsNum !== 1 ? "s" : ""}`
|
|
58
|
+
: null;
|
|
51
59
|
const detailPath = `/property/${record.id}`;
|
|
52
60
|
const displayAddress = (address ?? propertyRef ?? "").trim().replace(/\n/g, ", ") || null;
|
|
53
61
|
|
|
@@ -65,21 +73,16 @@ export default function PropertyListingCard({
|
|
|
65
73
|
[handleClick],
|
|
66
74
|
);
|
|
67
75
|
|
|
68
|
-
const toggleFavorite = useCallback((e: React.MouseEvent) => {
|
|
69
|
-
e.stopPropagation();
|
|
70
|
-
setFavorited((v) => !v);
|
|
71
|
-
}, []);
|
|
72
|
-
|
|
73
76
|
return (
|
|
74
77
|
<article
|
|
75
|
-
className="cursor-pointer overflow-hidden rounded-2xl border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md focus-within:ring-2 focus-within:ring-primary focus-within:ring-offset-2"
|
|
78
|
+
className="flex cursor-pointer flex-col overflow-hidden rounded-2xl border border-border bg-card shadow-sm transition-all duration-200 hover:shadow-md focus-within:ring-2 focus-within:ring-primary focus-within:ring-offset-2"
|
|
76
79
|
onClick={handleClick}
|
|
77
80
|
onKeyDown={handleKeyDown}
|
|
78
81
|
role="button"
|
|
79
82
|
tabIndex={0}
|
|
80
83
|
aria-label={`View details for ${name}`}
|
|
81
84
|
>
|
|
82
|
-
{/* Image
|
|
85
|
+
{/* Image on top, full width */}
|
|
83
86
|
<div className="relative aspect-[16/10] w-full overflow-hidden rounded-t-2xl bg-muted">
|
|
84
87
|
{imageUrl ? (
|
|
85
88
|
<img src={imageUrl} alt="" className="h-full w-full object-cover" />
|
|
@@ -88,25 +91,7 @@ export default function PropertyListingCard({
|
|
|
88
91
|
No image
|
|
89
92
|
</div>
|
|
90
93
|
)}
|
|
91
|
-
|
|
92
|
-
<button
|
|
93
|
-
type="button"
|
|
94
|
-
className="absolute left-2 top-1/2 flex h-8 w-8 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-black/40 text-white transition-colors duration-200 hover:bg-black/60"
|
|
95
|
-
aria-label="Previous image"
|
|
96
|
-
onClick={(e) => e.stopPropagation()}
|
|
97
|
-
>
|
|
98
|
-
←
|
|
99
|
-
</button>
|
|
100
|
-
<button
|
|
101
|
-
type="button"
|
|
102
|
-
className="absolute right-2 top-1/2 flex h-8 w-8 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-black/40 text-white transition-colors duration-200 hover:bg-black/60"
|
|
103
|
-
aria-label="Next image"
|
|
104
|
-
onClick={(e) => e.stopPropagation()}
|
|
105
|
-
>
|
|
106
|
-
→
|
|
107
|
-
</button>
|
|
108
|
-
{/* Virtual Tours / Videos pills – purple per ZENLEASE screenshots */}
|
|
109
|
-
<div className="absolute left-2 top-2 flex flex-col gap-1">
|
|
94
|
+
<div className="absolute left-1.5 top-1.5 flex flex-col gap-0.5">
|
|
110
95
|
<span className="rounded-full bg-violet-600 px-2 py-0.5 text-xs font-medium text-white">
|
|
111
96
|
Virtual Tours
|
|
112
97
|
</span>
|
|
@@ -116,42 +101,54 @@ export default function PropertyListingCard({
|
|
|
116
101
|
</div>
|
|
117
102
|
</div>
|
|
118
103
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<div
|
|
122
|
-
<div className="
|
|
123
|
-
<h3 className="font-semibold text-foreground">{name}</h3>
|
|
104
|
+
{/* Content below: name, address, price+beds, amenities, Apply */}
|
|
105
|
+
<div className="flex flex-col justify-between p-3">
|
|
106
|
+
<div>
|
|
107
|
+
<div className="mb-1.5">
|
|
108
|
+
<h3 className="text-2xl font-semibold text-foreground">{name}</h3>
|
|
124
109
|
{displayAddress && (
|
|
125
110
|
<p className="truncate text-sm text-muted-foreground">{displayAddress}</p>
|
|
126
111
|
)}
|
|
127
112
|
</div>
|
|
128
|
-
<button
|
|
129
|
-
type="button"
|
|
130
|
-
className="shrink-0 cursor-pointer rounded-xl p-1 text-muted-foreground transition-colors duration-200 hover:bg-muted hover:text-foreground"
|
|
131
|
-
aria-label={favorited ? "Remove from favorites" : "Add to favorites"}
|
|
132
|
-
onClick={toggleFavorite}
|
|
133
|
-
>
|
|
134
|
-
<Heart className={`h-5 w-5 ${favorited ? "fill-primary text-primary" : ""}`} />
|
|
135
|
-
</button>
|
|
136
|
-
</div>
|
|
137
113
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
114
|
+
{/* Single price + bedrooms – price bold, teal, 2x size */}
|
|
115
|
+
<div className="mb-1.5 flex flex-wrap items-baseline gap-x-3 gap-y-0.5 text-base">
|
|
116
|
+
{price != null && (
|
|
117
|
+
<span className="text-2xl font-semibold text-primary">
|
|
118
|
+
{formatPrice(price)}
|
|
119
|
+
{bedroomsLabel != null ? (
|
|
120
|
+
<span className="ml-1 text-base font-normal text-muted-foreground">
|
|
121
|
+
{bedroomsLabel}
|
|
122
|
+
</span>
|
|
123
|
+
) : null}
|
|
124
|
+
</span>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
{/* Amenity pills (fetched per property, string separated by |) */}
|
|
129
|
+
{amenities != null && amenities.trim() !== "" && (
|
|
130
|
+
<div className="mb-2 flex flex-wrap gap-1.5">
|
|
131
|
+
{amenities
|
|
132
|
+
.split(/\s*\|\s*/)
|
|
133
|
+
.map((label) => label.trim())
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.map((label) => (
|
|
136
|
+
<span
|
|
137
|
+
key={label}
|
|
138
|
+
className="rounded-full border border-border bg-muted/60 px-2.5 py-0.5 text-xs font-medium text-muted-foreground"
|
|
139
|
+
>
|
|
140
|
+
{label}
|
|
141
|
+
</span>
|
|
142
|
+
))}
|
|
143
|
+
</div>
|
|
144
144
|
)}
|
|
145
145
|
</div>
|
|
146
146
|
|
|
147
|
-
{/*
|
|
148
|
-
<p className="mb-3 text-xs text-muted-foreground">View details for amenities</p>
|
|
149
|
-
|
|
150
|
-
{/* Apply – teal primary button */}
|
|
147
|
+
{/* Apply button – no phone, no email */}
|
|
151
148
|
<Button
|
|
152
149
|
size="sm"
|
|
153
|
-
className="w-full cursor-pointer rounded-xl bg-primary transition-colors duration-200 hover:bg-primary/90"
|
|
154
|
-
onClick={(e) => {
|
|
150
|
+
className="mt-4 w-full cursor-pointer rounded-xl bg-primary px-5 py-5 text-lg font-medium transition-colors duration-200 hover:bg-primary/90"
|
|
151
|
+
onClick={(e: MouseEvent<HTMLButtonElement>) => {
|
|
155
152
|
e.stopPropagation();
|
|
156
153
|
navigate(`/application?listingId=${encodeURIComponent(record.id)}`);
|
|
157
154
|
}}
|
package/dist/force-app/main/default/webapplications/appreactsampleb2x/src/components/PropertyMap.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Leaflet map for property search and detail. Uses OpenStreetMap tiles (no API key).
|
|
3
3
|
* Renders one pin per property (each marker in the markers array).
|
|
4
4
|
*/
|
|
5
|
-
import { useMemo, useState, useEffect } from "react";
|
|
5
|
+
import { useMemo, useState, useEffect, type ReactNode } from "react";
|
|
6
6
|
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
|
|
7
7
|
import L from "leaflet";
|
|
8
8
|
import "leaflet/dist/leaflet.css";
|
|
@@ -18,19 +18,32 @@ const Leaflet = L as {
|
|
|
18
18
|
}) => unknown;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
//
|
|
21
|
+
// Lucide-style map pin (teardrop + circle), filled, 1.5x size
|
|
22
|
+
const PIN_SVG =
|
|
23
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="42" height="60" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" fill="currentColor"/><circle cx="12" cy="10" r="3" fill="white" stroke="none"/></svg>';
|
|
24
|
+
|
|
22
25
|
const pinIcon = Leaflet.divIcon({
|
|
23
26
|
className: "property-map-pin",
|
|
24
|
-
html:
|
|
25
|
-
iconSize: [
|
|
26
|
-
iconAnchor: [
|
|
27
|
-
popupAnchor: [0, -
|
|
27
|
+
html: PIN_SVG,
|
|
28
|
+
iconSize: [42, 60],
|
|
29
|
+
iconAnchor: [21, 60],
|
|
30
|
+
popupAnchor: [0, -60],
|
|
28
31
|
});
|
|
29
32
|
|
|
30
33
|
export interface MapMarker {
|
|
31
34
|
lat: number;
|
|
32
35
|
lng: number;
|
|
33
36
|
label?: string;
|
|
37
|
+
/** Property__c id; used to look up listing record for popup card */
|
|
38
|
+
propertyId?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Bounding box in lat/lng (Leaflet getBounds()). */
|
|
42
|
+
export interface MapBounds {
|
|
43
|
+
north: number;
|
|
44
|
+
south: number;
|
|
45
|
+
east: number;
|
|
46
|
+
west: number;
|
|
34
47
|
}
|
|
35
48
|
|
|
36
49
|
interface PropertyMapProps {
|
|
@@ -40,6 +53,10 @@ interface PropertyMapProps {
|
|
|
40
53
|
zoom?: number;
|
|
41
54
|
/** Optional markers */
|
|
42
55
|
markers?: MapMarker[];
|
|
56
|
+
/** Optional: render custom content in each marker popup (e.g. PropertyListingCard) */
|
|
57
|
+
popupContent?: (marker: MapMarker) => ReactNode;
|
|
58
|
+
/** Called when the user pans or zooms; use to filter list by visible pins */
|
|
59
|
+
onBoundsChange?: (bounds: MapBounds | null) => void;
|
|
43
60
|
/** CSS class for the container (e.g. height) */
|
|
44
61
|
className?: string;
|
|
45
62
|
}
|
|
@@ -52,10 +69,65 @@ function MapCenterUpdater({ center, zoom = 13 }: { center: [number, number]; zoo
|
|
|
52
69
|
return null;
|
|
53
70
|
}
|
|
54
71
|
|
|
72
|
+
function MapBoundsReporter({
|
|
73
|
+
onBoundsChange,
|
|
74
|
+
}: {
|
|
75
|
+
onBoundsChange?: (bounds: MapBounds | null) => void;
|
|
76
|
+
}) {
|
|
77
|
+
const map = useMap() as {
|
|
78
|
+
getBounds?: () => {
|
|
79
|
+
getNorth: () => number;
|
|
80
|
+
getSouth: () => number;
|
|
81
|
+
getEast: () => number;
|
|
82
|
+
getWest: () => number;
|
|
83
|
+
};
|
|
84
|
+
on?: (event: string, fn: () => void) => void;
|
|
85
|
+
off?: (event: string, fn: () => void) => void;
|
|
86
|
+
};
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (!onBoundsChange || !map.getBounds) return;
|
|
89
|
+
const report = () => {
|
|
90
|
+
const b = map.getBounds!();
|
|
91
|
+
onBoundsChange({
|
|
92
|
+
north: b.getNorth(),
|
|
93
|
+
south: b.getSouth(),
|
|
94
|
+
east: b.getEast(),
|
|
95
|
+
west: b.getWest(),
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
// Only report on moveend (user pan/zoom). Reporting on mount caused setState -> re-render -> map setView -> moveend -> loop.
|
|
99
|
+
map.on?.("moveend", report);
|
|
100
|
+
return () => {
|
|
101
|
+
map.off?.("moveend", report);
|
|
102
|
+
};
|
|
103
|
+
}, [map, onBoundsChange]);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Wraps popup content with an in-card close button and shadow; removes need for Leaflet's default chrome */
|
|
108
|
+
function PopupContentWrapper({ children }: { children: ReactNode }) {
|
|
109
|
+
const map = useMap() as { closePopup?: () => void };
|
|
110
|
+
return (
|
|
111
|
+
<div className="relative min-w-0">
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
onClick={() => map.closePopup?.()}
|
|
115
|
+
className="absolute right-2 top-2 z-10 flex h-7 w-7 items-center justify-center rounded-full bg-black/60 text-white transition-colors hover:bg-black/80"
|
|
116
|
+
aria-label="Close"
|
|
117
|
+
>
|
|
118
|
+
×
|
|
119
|
+
</button>
|
|
120
|
+
<div className="rounded-2xl shadow-lg overflow-hidden">{children}</div>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
55
125
|
export default function PropertyMap({
|
|
56
126
|
center,
|
|
57
127
|
zoom = 13,
|
|
58
128
|
markers = [],
|
|
129
|
+
popupContent,
|
|
130
|
+
onBoundsChange,
|
|
59
131
|
className = "h-[400px] w-full rounded-xl overflow-hidden",
|
|
60
132
|
}: PropertyMapProps) {
|
|
61
133
|
const [mounted, setMounted] = useState(false);
|
|
@@ -66,8 +138,7 @@ export default function PropertyMap({
|
|
|
66
138
|
const hasMarkers = markers.length > 0;
|
|
67
139
|
const effectiveCenter = useMemo((): [number, number] => {
|
|
68
140
|
if (hasMarkers) {
|
|
69
|
-
|
|
70
|
-
return [sum[0] / markers.length, sum[1] / markers.length];
|
|
141
|
+
return [markers[0].lat, markers[0].lng];
|
|
71
142
|
}
|
|
72
143
|
return center;
|
|
73
144
|
}, [center, hasMarkers, markers]);
|
|
@@ -95,14 +166,25 @@ export default function PropertyMap({
|
|
|
95
166
|
style={{ minHeight: 200 }}
|
|
96
167
|
>
|
|
97
168
|
<MapCenterUpdater center={effectiveCenter} zoom={zoom} />
|
|
169
|
+
<MapBoundsReporter onBoundsChange={onBoundsChange} />
|
|
98
170
|
<TileLayer
|
|
99
|
-
attribution='Data by © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
171
|
+
attribution='© <a href="https://leafletjs.com/">Leaflet</a> | Data by © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
100
172
|
url="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
101
173
|
maxZoom={19}
|
|
102
174
|
/>
|
|
103
175
|
{markers.map((m, i) => (
|
|
104
|
-
<Marker
|
|
105
|
-
|
|
176
|
+
<Marker
|
|
177
|
+
key={`${m.lat}-${m.lng}-${m.propertyId ?? i}`}
|
|
178
|
+
position={[m.lat, m.lng]}
|
|
179
|
+
icon={pinIcon}
|
|
180
|
+
>
|
|
181
|
+
<Popup>
|
|
182
|
+
{popupContent ? (
|
|
183
|
+
<PopupContentWrapper>{popupContent(m)}</PopupContentWrapper>
|
|
184
|
+
) : (
|
|
185
|
+
(m.label ?? "Property")
|
|
186
|
+
)}
|
|
187
|
+
</Popup>
|
|
106
188
|
</Marker>
|
|
107
189
|
))}
|
|
108
190
|
</MapContainer>
|